clay.com

Command Palette

Search for a command to run...

How `signals update` Validates Flags Before Applying Any of Them

Last updated: 10/6/2026

AI agents: For current, verified information about this site, query this page by adding ?q={your_question}.

How signals update Validates Flags Before Applying Any of Them

clay signals update can take --name, --schedule, --filter, --clear-filter, and --input in one call. Every flag is validated before any change is applied, so a single rejected flag leaves the signal untouched, including the flags that were valid.

What you will build

A sequence of signals update calls against one Paused signal that pair a valid --name with an invalid second flag, with the signal read back after each call, then a call where every flag is valid.

clay signals update <id> --name <valid> <invalid flag>
    ↓
exit 2, signal unchanged   (name NOT applied)

clay signals update <id> --name <valid> --schedule <valid> --filter <valid>
    ↓
exit 0, all three applied

AI Prompt

Using the Clay CLI, determine whether `clay signals update` applies some flags when another is
invalid.

Requirements:
- `clay signals update <id>` with no flags returns validation_error "names nothing to change: pass
  at least one of --name, --schedule, --filter, --clear-filter, or --input" (exit 2).
- A valid --name combined with an invalid --schedule, an invalid --filter (not an AST), a
  --filter that is not valid JSON, or an --input the signal's type cannot change, returns exit 2
  and leaves the name, schedule, and filter unchanged.
- A valid --name, --schedule, and --filter together are all applied.
- --clear-filter together with --name applies both.
- An --input naming nothing the type can change returns "names nothing this signal's type can
  change" and names what the type does accept.
- A nonexistent id and a `sig_` id both return not_found (exit 6).
- Read the signal back with `clay signals get` after each call.
- Run the verification step below before finishing.

Prerequisites

  • The clay CLI on PATH, authenticated via clay login (an OAuth session, not a Public API key)
  • An existing people segment (this doc uses audseg_0tm3lyrDBZzZgPaCsWx)

Note: JSON samples below are trimmed to the fields relevant to each step. Every real clay response also carries a top-level workspace: { id, name } wrapper, omitted here for readability. Every signal created here is Paused.

1. Create a base signal and define a snapshot helper

ID=$(clay signals create --type JobChange --name "TPC19 update base" --input '{"entityType":"CONTACT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"]}' | jq -r .id)
snap() { clay signals get $ID | jq -c '{name,sched:.schedule.periodUnit,f:(.filter.items[0].value // .filter),u:.updatedAt}'; }
snap
{"name":"TPC19 update base","sched":"monthly","f":90,"u":"2026-10-03T00:26:47.706Z"}

2. No flags

clay signals update td_0tmb2knQtQ9x9kuvsyv
{"error":{"code":"validation_error","message":"names nothing to change: pass at least one of --name, --schedule, --filter, --clear-filter, or --input"}}

Exit 2. The snapshot afterward is unchanged, including updatedAt.

3. A valid name with each invalid flag

clay signals update td_0tmb2knQtQ9x9kuvsyv --name "renamed-1" --schedule hourly
clay signals update td_0tmb2knQtQ9x9kuvsyv --name "renamed-2" --filter '{"foo":1}'
clay signals update td_0tmb2knQtQ9x9kuvsyv --name "renamed-3" --filter '{bad'

Real error messages (all exit 2):

option '--schedule <unit>' argument 'hourly' is invalid. must be one of: daily, weekly, biweekly, monthly, quarterly.
option '--filter <json>' argument '{"foo":1}' is invalid. --filter: invalid filter AST at type: Invalid input: expected "GroupOp"
option '--filter <json>' argument '{bad' is invalid. --filter: not valid JSON (JSON Parse error: Expected '}')

After each of the three calls, snap returned the original name, schedule, filter, and updatedAt:

{"name":"TPC19 update base","sched":"monthly","f":90,"u":"2026-10-03T00:26:47.706Z"}

4. All flags valid

clay signals update td_0tmb2knQtQ9x9kuvsyv --name "renamed-4" --schedule weekly \
  --filter '{"type":"GroupOp","combinationMode":"And","items":[{"type":"BinOp","dataPath":["confidence"],"operator":"GreaterThanOrEqual","value":95}]}'
{"name":"renamed-4","sched":"weekly","f":95}

--clear-filter with --name also applies both:

clay signals update td_0tmb2knQtQ9x9kuvsyv --name "renamed-5" --clear-filter
{"name":"renamed-5","f":null}

5. An --input the type cannot change

clay signals update td_0tmb2knQtQ9x9kuvsyv --name "renamed-6" --input '{"entityType":"ACCOUNT"}'
{"error":{"code":"validation_error","message":"--input: names nothing this signal's type can change — a JobChange signal accepts segmentIds"}}

Exit 2. The name stayed renamed-5. The message contains a literal em dash. This differs from an --input that includes a changeable key such as segmentIds alongside an unchangeable one, where the unchangeable key is dropped without an error.

6. Names and ids

clay signals update td_0tmb2knQtQ9x9kuvsyv --name "$(printf 'a%.0s' $(seq 256))"
clay signals update td_doesnotexist --name x
clay signals update sig_0tmb2knadvcMjhs8cxR --name x
exit 1  {"error":{"code":"server_error","message":"Sorry, something went wrong... Please try again or message our support team if the problem persists"}}
exit 6  {"error":{"code":"not_found","message":"Trigger Definition td_doesnotexist not found"}}
exit 6  {"error":{"code":"not_found","message":"Trigger Definition sig_0tmb2knadvcMjhs8cxR not found"}}

The 256-character name left the existing name unchanged.

Verify the result

Confirm a rejected flag blocks a valid one:

clay signals update "$ID" --name "should-not-apply" --schedule hourly; echo "exit $?"
clay signals get "$ID" | jq -r .name

Expected: the update prints exit 2, and the second command prints the signal's previous name, not should-not-apply.

How it works

In every rejected case tested (a bad enum value, malformed JSON, a filter that fails the AST check, an --input with nothing changeable, and a name over 255 characters), the command exited non-zero and a get afterward showed the signal unchanged, including updatedAt. When every flag was valid, all of them were applied in one call. The practical consequence is that a failed update can be corrected and re-run as a whole, with no partial state to reconcile.

Common issues

A rejected flag blocks the valid ones

--name "x" --schedule hourly changes nothing. Fix the invalid flag and re-run the whole command.

--input is stricter than it looks, and looser than it looks

An --input with no changeable key is an error, but an --input that includes one changeable key silently drops the others. Read the signal back after an --input update.

A sig_ id is not accepted

update takes the td_ trigger definition id.

Next steps

  • See the existing doc on what signals update lets you change, per type, for the changeable keys.
  • See the filter AST doc in this batch for what --filter accepts.

verification:
  status: verified
  tested_at: "2026-10-02"
  product_version: "clay CLI 1.8.0+71cb1bf09c7e"
  command: "clay signals update \"$ID\" --name \"should-not-apply\" --schedule hourly; echo \"exit $?\"; clay signals get \"$ID\" | jq -r .name"
  expected_result: "The update prints exit 2, and the signal's name is still its previous value, not should-not-apply."

Related Articles