Skip to content

validation_failed

A field, query parameter or header has a value the endpoint can’t accept.

HTTP 400 · invalid_request_error · not retryable

A field, query parameter or header has a value the endpoint can’t accept. param names it, using dots for nested JSON members (items.0.amount). The pipeline sends it for:

  • an unknown JSON member (“amout isn’t a known field. Check the spelling, or the API version.”)
  • a JSON value of the wrong type (“limit has the wrong type: it must be a whole number.”)
  • a limit outside 1–100, or a cursor this API didn’t issue

Renaming an agent is 422, with this code. Sending name in PATCH /v1/agents/{id} answers 422 validation_failed with param: "name": “Agent names can’t change, because policies match on them. To rename, create a new agent with the new name and move its keys.” Names are immutable because policies match on them (AGENTS.md).

The on-behalf-of headers are 422, with this code. A Deedglass-On-Behalf-Of or Deedglass-Session header that doesn’t match ^[A-Za-z0-9._~:@/+=-]{1,256}$, or is sent twice, answers 422 validation_failed with param set to the header name: “Deedglass-On-Behalf-Of must be 1 to 256 characters: letters, digits and . _ ~ : @ / + = -. Use an opaque user id, not a name.” (for Deedglass-Session: “… Use an opaque conversation or run id.”), or “Send Deedglass-On-Behalf-Of once. It names one person or session per call.” It is checked on every request an API key authenticates (IDENTITY.md, On-behalf-of).

The Gate’s checks. POST /v1/actions refuses a malformed request before anything is recorded:

Param Message
args args is 312 KiB; the limit is 256 KiB. Send a reference to the data instead of the data itself.
args args is nested more than 32 levels deep. Flatten it, or send a reference to the data.
args args contains an integer larger than 9007199254740991, which JSON can't carry exactly. Send it as a string.
args args must be a JSON object. Send the tool's arguments as an object, {} when it takes none.
tool tool is empty. Name a tool as "connector.tool", for example "fake.echo".
mode mode must be gateway or proxy (got "{mode}"). Leave it out for gateway, where Deedglass runs the tool.
wait wait must be a number of seconds from 0 to 25.
connector_type connector_type is for proxy mode, where the edge runs the tool. In gateway mode Deedglass knows the connector; leave connector_type out.

POST /v1/actions/{id}/result checks the edge’s report the same way: status (“status must be succeeded, failed or unknown.”), the times, error_code, and result_digest, which must match result (“result_digest doesn’t match result. Send the digest of the exact result (sha256 of its RFC 8785 form), or leave it out.”). GET /v1/actions/{id} takes only wait (0 to 25 seconds, sent once) and expand[].

Connector read-backs. Creating or updating a connector checks each write tool’s readback and postcondition (CONNECTORS.md). param is the field’s path in the config; when several fields are wrong, the message names the first and says how many there are:

Param Message
config.tools[1].readback.tool "update_status" writes, so it can't be a read-back. Name a read tool such as "get".
config.tools[1].readback.tool "list" isn't idempotent, so it can't be a read-back. Name a read tool that is.
config.tools[1].readback.attempts attempts above 1 need consistency: eventual.
config.tools[1].postcondition A postcondition needs a read-back to read from. Add readback: { tool: get, args: … } to this tool.
config.tools[1].postcondition 1:28: request.status isn't a field. Did you mean args.status?
config.tools[1].postcondition This condition could cost up to 520,488,451 units per call; the limit is 100,000. Compare fewer fields, or use expect.

Fix the field the message names, then retry.

HTTP 400 · validation_failed
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "`limit` must be between 1 and 100.",
"param": "limit",
"request_id": "req_01j9zr3m5k8q2w7x4t6v0b1c9d",
"doc_url": "https://docs.deedglass.com/errors/validation_failed"
}
}

The message is for a person and can get more exact over time: branch on type and code, never on the message.

SDK Raised as
TypeScript (@deedglass/sdk) InvalidRequestError with code === "validation_failed"
Python (deedglass) deedglass.InvalidRequestError with .code == "validation_failed"