Deleting an Audience Field: Two Different Silent Failure Modes
?q={your_question}.Deleting an Audience Field: Two Different Silent Failure Modes
Delete a custom field definition and see what actually happens to any audience filtering on it, using clay audiences fields delete, which behaves in two different ways depending on how the referencing filter was built, neither of which errors or warns.
What you will build
A field-delete workflow that checks what depends on a field first, then confirms both real outcomes: an ACCOUNT/CONTACT-typed reference gets rewritten (and can silently widen), while a CUSTOM-typed reference is left dangling (pointing at a field that no longer exists).
clay audiences fields segments <fieldId> --entity-type <type> (finds ACCOUNT/CONTACT refs only)
↓
clay audiences fields delete <fieldId> --entity-type <type> (always {"ok": true})
↓
clay audiences get <audience-id>
→ ACCOUNT/CONTACT clause: removed, filter rewritten (possibly to items: [])
→ CUSTOM clause: unchanged, still keying on the deleted field id
AI Prompt
Using the Clay CLI, delete a custom audience field and confirm the effect on
any audience filtering on it.
Requirements:
- `clay audiences fields delete <fieldId> --entity-type <people|companies>`.
Deleting is a soft delete and idempotent; deleting an unknown or
already-deleted field id still exits 0. Default and system fields cannot
be deleted (validation_error).
- Deleting a field rewrites every saved audience whose filter references it
via entityType ACCOUNT or CONTACT, removing just that clause, with no
error or warning. If the clause was the audience's only condition, the
filter becomes an empty group ({"type":"GroupOp","combinationMode":"And",
"items":[]}), which matches every record of that entity type: a
filtered audience can silently become "everything."
- This rewrite does not happen for a clause using entityType "CUSTOM".
Deleting the field still succeeds ({"ok":true}), but the audience's
filter is left completely unchanged, still keying on the now-deleted
field id. The audience is left with a dangling reference: `audiences
get`, `update`, `records search-count`, and `records search-ids` all
still succeed (exit 0) against that dangling filter, silently. This is
the opposite failure mode from the ACCOUNT/CONTACT case: the audience
stays narrow (now matching nothing meaningful, since the field it
filters on no longer exists) rather than silently widening.
- `clay audiences fields segments <fieldId> --entity-type <type>` lists
which saved audiences reference a field; run this before deleting. It
correctly finds ACCOUNT/CONTACT-typed references, but does not find
CUSTOM-typed ones, and the rewrite scope exactly matches what `segments`
finds. So a field only referenced via CUSTOM shows zero dependents in
`segments`, deletes cleanly, and leaves a dangling filter behind with no
warning anywhere in the process.
- Prefer ACCOUNT/CONTACT entityType for custom field filters specifically
so `segments` (and the delete-time rewrite) can see the reference at all.
- Run the verification step below before finishing.
Prerequisites
- The
clayCLI on PATH, authenticated viaclay login(an OAuth session, not a Public API key) jq
Note: JSON samples below are trimmed to the fields relevant to each step. Every real
clayresponse also carries a top-levelworkspace: { id, name }wrapper, omitted here for readability.
1. Create a field and an audience that filters on it
clay audiences fields create --entity-type companies --name "Delete Test Field" --data-type text
clay audiences create --entity-type companies --name "Field-Delete Demo" \
--filter '{"type":"GroupOp","combinationMode":"And","items":[{"type":"BinOp","key":"<fieldId>","dataPath":["account_entity_field_values","field","<fieldId>"],"operator":"Equal","value":"gold","entityType":"ACCOUNT"}]}'
2. Check what references the field before deleting
clay audiences fields segments <fieldId> --entity-type companies
Real output, the demo audience is correctly found:
{"data": [{"id": "audseg_0tlqasyTWEey4gZhuvp", "name": "Field-Delete Demo 2", "entityType": "companies"}]}
3. Delete the field
clay audiences fields delete <fieldId> --entity-type companies
Real output:
{"ok": true}
4. Confirm the audience's filter was rewritten, and widened
clay audiences get audseg_0tlqasyTWEey4gZhuvp
Real output, the clause referencing the deleted field is simply gone, leaving an empty group:
{
"id": "audseg_0tlqasyTWEey4gZhuvp",
"name": "Field-Delete Demo 2",
"filter": {"type": "GroupOp", "combinationMode": "And", "items": []}
}
An empty And group matches every company record. This audience went from "gold-tier companies" to "all companies" the instant the field was deleted, with no error and no warning in the delete response.
5. Repeat with a CUSTOM-typed reference: the opposite outcome
clay audiences fields create --entity-type companies --name "Custom Dangling Test" --data-type text
clay audiences create --entity-type companies --name "Custom Dangling Demo" \
--filter '{"type":"GroupOp","combinationMode":"And","items":[{"type":"BinOp","key":"<fieldId2>","dataPath":["account_entity_field_values","field","<fieldId2>"],"operator":"Equal","value":"gold","entityType":"CUSTOM"}]}'
clay audiences fields segments <fieldId2> --entity-type companies
clay audiences fields delete <fieldId2> --entity-type companies
clay audiences get <that-audience-id>
Real output, reproduced independently: fields segments returns an empty list (misses the CUSTOM reference entirely), the delete still succeeds, and the audience's filter is completely unchanged, still keying on the now-deleted field id:
{
"id": "audseg_0tlqcr8t47Aq47Qj8n8",
"filter": {
"type": "GroupOp", "combinationMode": "And",
"items": [{"type": "BinOp", "key": "audf_0tlqcr3nndJnmt47EcK", "operator": "Equal", "value": "gold", "entityType": "CUSTOM"}]
}
}
audf_0tlqcr3nndJnmt47EcK no longer exists as a field (confirmed absent from fields list), yet the audience still references it, and audiences get/update/records search-count all still succeed against this dangling filter with no error anywhere.
Verify the result
Confirm the behavior above holds by re-running the key commands and checking the result:
clay audiences fields segments <fieldId> --entity-type companies && clay audiences fields delete <fieldId> --entity-type companies && clay audiences get <audience-id>
Expected: for an ACCOUNT/CONTACT-typed reference, fields segments finds it beforehand and the audience's filter has the clause removed after deletion (possibly down to items: [], matching everything). For a CUSTOM-typed reference, fields segments finds nothing, the delete still succeeds, and the audience's filter is left completely unchanged, dangling on a field id that no longer exists. Neither path produces an error or warning.
How it works
The rewrite-on-delete behavior is scoped to exactly what fields segments can see, which is ACCOUNT/CONTACT-typed filter clauses, not CUSTOM-typed ones. The same indexing that identifies "what references this field" also drives what gets cleaned up when the field is deleted. The two resulting outcomes are opposite in character: an ACCOUNT/CONTACT audience silently widens (the constraint is removed), while a CUSTOM audience silently stays narrow but now filters on nothing real (the constraint is dead weight, keyed to a field that doesn't exist). Neither outcome produces a warning, and neither is caught by fields segments, get, update, or search-count/search-ids, all of which succeed against the affected audience either way.
Common issues
Trusting fields segments to catch every reference
It's natural to assume fields segments indexes any BinOp mentioning the field id, regardless of entityType. In practice, a reference using entityType: "CUSTOM" is not surfaced by fields segments, while the same field referenced with entityType: "ACCOUNT" is. Use ACCOUNT/CONTACT for custom-field filters specifically so segments (and the delete-time rewrite) can see the reference at all.
Assuming every affected audience gets rewritten to something wider
The ACCOUNT/CONTACT case (the one fields segments catches) does widen, but a CUSTOM-typed reference is left completely unchanged, not rewritten: the audience keeps its original filter, now pointing at a nonexistent field. This is a dangling reference, not a widened one, and fields segments won't surface it either.
Next steps
- After deleting a field that had ACCOUNT/CONTACT dependents, re-run
search-count --entity-type <type>on each affected audience to see its new, likely-wider match count. - Prefer
fields update --hidden trueover deletion when you're unsure whether a field is still load-bearing. Hiding doesn't touch any filter, and works regardless of the referencing clause's entityType.
verification: status: verified tested_at: "2026-09-21" product_version: "clay CLI 1.2.0" command: "clay audiences fields delete <fieldId> --entity-type companies && clay audiences get <audience-id>" expected_result: "For an ACCOUNT-typed reference, the field is deleted and the audience's filter clause is removed (possibly down to items: [], matching every company record). For a CUSTOM-typed reference, the field is deleted but the audience's filter is left completely unchanged, still keying on the deleted field id."