Clear a single field value on a collection
DELETE /collections/{id}/fields/{field_id}
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Query Parameters
Section titled “Query Parameters ”PER-FIELD optimistic concurrency for a removal (#1119). The
token is the value row’s own set_at, as
CollectionFieldValueWrite.if_unchanged_since describes it. The
row is deleted only if it still carries exactly that
set_at; otherwise the operation answers 409 with
CollectionFieldValueConflict and DELETES NOTHING — a stale
removal must not erase a newer value it never saw.
It rides in the query string because a DELETE carries no
body. There is no if_absent companion: “remove it only if
it is not there” has nothing to remove.
Omitting it is the unguarded removal this endpoint has always performed, 204 whether or not a row existed, kept for callers that are not an edit surface.
Responses
Section titled “ Responses ”Cleared
Malformed request
object
Human-readable error summary
Example
the request could not be completedAuthentication required, missing, or invalid
object
Human-readable error summary
Example
the request could not be completedExample
{ "error": "authentication required: sign in and retry with a valid session or API token"}Authenticated but missing required capabilities
object
Human-readable error summary
Example
the request could not be completedResource not found
object
Human-readable error summary
Example
the request could not be completedThe guarded write was refused: the stored value is not the version the caller guarded against, and nothing was stored.
The collection twin of AssetFieldValueConflict, with the same
contract: nothing was stored, current is required and
nullable, and present: false carries current: null with no
fabricated set_at. Two schemas rather than one because
current is a different value shape on each subject kind.
object
The value as stored now, or JSON null when present is
false.
object
Display data for the vocabulary slugs this value holds, keyed by slug. Present only for select / multi_select / tree, and only for slugs that resolve against the field’s options document — a slug with no entry is absent and the caller falls back to the slug itself. Mirrors AssetFieldValue.resolved_options exactly (#840): collection metadata resolves the same way asset metadata does, so a select value renders its label and not its raw slug.
object
One controlled-vocabulary term as a reader needs to see it.
Note there is no value — the map key is the slug.
object
Display text. Equal to the slug when the term carries no explicit label, which is the case for every option written in the bare-string form (see ADR 0012’s 2026-07-30 correction) — so a caller can always render this directly.
The term’s lifecycle state. A reader should mark anything other than active, so a value stops looking current the moment an operator retires the term behind it.
Ancestor labels from the root of the field’s vocabulary down
to and including this term — what a tree value needs in
order to display as “Europe / United Kingdom / London” when
the stored value is nothing but london.
Absent for any term that sits at the top level, which is
every term in a flat select / multi_select vocabulary: a
one-element path would say nothing label does not. So a
caller renders path.join(...) when it is present and
label when it is not.
The asset a reference value points at, as a reader needs to
see it. Present only for reference values whose value_ref
resolves to an asset this caller may see.
Absent is meaningful and load-bearing: it means the target
did not resolve — soft-deleted, or a dangling ref to a row that
no longer exists. A client MUST fall back to rendering the bare
value_ref UUID and MUST NOT treat the absence as an error.
Degrading to the id keeps the panel intact and leaks nothing:
the id was already on the record the caller is reading.
This mirrors resolved_options exactly, and for the same
reason (#775): the row carrying the value already joins the row
carrying the display text, so the server pays the resolution
once for every consumer rather than letting each display
surface print a raw UUID.
object
The target asset’s id. Equal to the enclosing value’s
value_ref — repeated here so a client holding a
resolved_reference never has to reach back out of it to
build the /assets/{id} link.
The target asset’s title. May be the empty string —
assets.title defaults to '' and nothing requires an
uploader to set one — so a client renders the id when this
is blank rather than an empty link.
The request is well-formed but the value cannot be stored.
ONE response shared by the asset and the collection field-value
writers, so the two cannot drift into describing the same
refusal differently. field is the field’s code and option
the slug that was refused, so a client can point at the
offending term without parsing error.
field_not_for_collection— the field is asset-scoped.value_type_mismatch— the value is in the wrong member for the field’s declared type.unknown_option—select/multi_select/treeonly: the slug is not in the field’s controlled vocabulary.option_not_offerable— the slug names a deprecated or archived term the record did not already hold. Terms are never hard-deleted, so a value already carrying a retired slug keeps saving; only changing to one is refused.dangling_reference—referenceonly:value_refnames an asset that does not resolve. Refused on write; a value whose target is deleted after a valid write still reads (bare id).vocabulary_extension_forbidden— the field is open and the term would have been created, but the caller does not holdfields.vocabulary.extend.field_read_only— the field declaresread_only, so a person may not set or clear its values.pattern_mismatch— the value does not match the field’sregexp_filteracross its whole length.field_required— the field declaresrequired, so a person may neither write an empty value into it nor remove the value it holds (#1389).
Why a well-formed field-value write could not be stored.
ONE body shared by the asset and the collection writers (both
return it via the FieldValueUnprocessable response), so the two
cannot drift into describing the same refusal differently.
field is the field’s code and option the slug that was
refused, so a client can point at the offending term without
parsing error.
object
-
field_not_for_collection— the field is asset-scoped and cannot be written on a collection. -
value_type_mismatch— the value arrived in the wrong value_* member for the field’s declared type. -
unknown_option—select/multi_select/treeonly: the slug is not a term in the field’s controlled vocabulary. Fortreethe whole option tree is searched, not just the top level, and a branch slug is as valid as a leaf. -
option_not_offerable— the slug names a deprecated or archived term that the record did not already hold. Options are never hard-deleted, so a record already carrying a since-retired term keeps saving; only changing to one is refused. -
dangling_reference—referenceonly:value_refnames an asset that does not resolve (never existed, or has been deleted). Refused on WRITE so a value cannot be pointed at a nonexistent asset. Note the asymmetry with READ: a value that resolved when written and whose target is deleted later still reads fine, degrading to the bare id (resolved_referencesimply absent) — the write gate does not retroactively invalidate it. -
vocabulary_extension_forbidden— the field IS open, and the term would have been created, but this caller does not holdfields.vocabulary.extend. Distinct fromunknown_optionon purpose: the term is absent in both cases, but here the fix is a grant rather than a correction, and a client that cannot tell them apart cannot say which. Reported per TERM rather than as a bare 403 because a write may carry five terms of which four already exist — naming the one that was refused is strictly more useful than refusing the principal. -
field_read_only— the field declaresread_only, so a person may not set or clear its values (#1173). NOT a 403: no capability grants this and no grant would lift it, so reporting it as a permission problem would send the operator hunting for a role that does not exist. The field’s configuration is the thing to change. -
pattern_mismatch— the field declares aregexp_filterand the supplied value does not match it across its whole length. Applies to human writes only; defaults and extraction are not checked, so a stored value may legitimately fail the pattern a new one is held to. -
field_required— the field declaresrequired, so a person may neither write an EMPTY value into it nor remove the value it holds (#1389). What “empty” means is per type: NULL or whitespace-only text; amulti_selectwith no members; a NULLvalue_num,value_dateorvalue_ref; and forrich_text, markup carrying no visible words, since the sanitiser strips no empty elements and<p><br></p>would otherwise pass. FALSE is a real boolean value and is never empty.The rule is the LATER-write rule and applies to the ordinary asset and collection field-value paths. It is not a completeness gate: asset creation still requires nothing, and collection create keeps its own separate
required_collection_field_missingrefusal. Human writes only — upload defaults, extraction and the mirrored-column filler are unaffected, exactly as withfield_read_only.
The code of the field that refused the value.
The offending slug, for the two vocabulary reasons. Null otherwise.