Skip to content

intent_invalid

The agent’s mode is optional or required, a Deedglass-Intent header was sent, and one of checks 1 to 12 failed §6 has the order).

HTTP 403 · permission_error · not retryable

The agent’s mode is optional or required, a Deedglass-Intent header was sent, and one of checks 1 to 12 failed §6 has the order). The logged reason says which. POST /v1/intents/verify checks the header in every mode, off included. It is 403, never 401.

Reason Param Message
syntax Deedglass-Intent The Deedglass-Intent header must be two base64url parts joined by a dot: the intent, then its signature.
too_large Deedglass-Intent The signed intent is larger than 2,048 bytes. Keep only the fields listed at docs.deedglass.com/intents.
strict Deedglass-Intent The signed intent isn't strict JSON: {detail}. Use the SDK signer, or follow the profile at docs.deedglass.com/intents.
not_canonical Deedglass-Intent The signed intent isn't canonical JSON (RFC 8785): keys must be sorted and there must be no whitespace. Use the SDK signer, or canonicalize before signing.
schema (unknown field) the field The signed intent has an unknown field "{field}". Put arguments in the call, and their digest in args_digest.
schema (missing field) the field The signed intent is missing the field "{field}". Sign every required field listed at docs.deedglass.com/intents.
schema (wrong type or pattern) the field The signed intent's {field} isn't valid: it must be {want}. See the field table at docs.deedglass.com/intents.
version v The signed intent's version is "{got}", and Deedglass reads deedglass.intent/1. Sign with deedglass.intent/1.
org_mismatch org The signed intent names {intent_org}, but this API key belongs to {org}. Sign with the agent's own org id.
agent_mismatch agent The signed intent names {intent_agent}, but this API key belongs to {agent} ({agent_id}). Sign with the agent's own identity.
unknown_kid kid The signed intent uses key {kid}, which isn't registered for {agent}. Register it with deedglass agent intent add {agent}, or in Console › Agents › Security.
bad_signature kid The signature doesn't verify with key {kid}. Sign the bytes "deedglass/intent/v1\n" + intent_hash with the matching private key.
not_yet_valid iat The signed intent was issued {ahead} in the future. Check the agent's clock; Deedglass allows 60 seconds of skew.
expired exp The signed intent expired at {time} UTC, {ago} ago. Sign a fresh intent for each call; an intent lasts at most 5 minutes.
ttl exp The signed intent is valid for {ms} ms, and it must be more than 0 and at most 300000 (5 minutes). Sign it again with exp after iat, at most 5 minutes later.
tool_mismatch tool The signed intent is for {intent_tool}, but this call is for {tool}. Sign one intent per call.
big_int args The arguments contain an integer larger than 9007199254740991, which JSON can't carry exactly. Send it as a string.
args_not_canonicalizable args The arguments can't be canonicalized with RFC 8785: {detail}. Send JSON with unique keys, at most 32 levels deep and at most 256 KiB.
args_mismatch args_digest The signed intent's args_digest doesn't match the arguments sent. Sign the exact arguments you send, canonicalized with RFC 8785.
unsigned_obo Deedglass-On-Behalf-Of or Deedglass-Session {name} was sent, but the signed intent doesn't include {field}. Sign it too, or leave the header out.
obo_mismatch Deedglass-On-Behalf-Of Deedglass-On-Behalf-Of says {header}, but the signed intent says {intent}. When you sign an intent, send the same value in both, or only in the intent.
session_mismatch Deedglass-Session Deedglass-Session says {header}, but the signed intent says {intent}. When you sign an intent, send the same value in both, or only in the intent.

{placeholders} are filled at the call site. INTENTS.md §6 lists every {detail} and {want}. A message never quotes the header itself.

Read the message: it names the field and the fix. Most refusals come from signing something other than what you send. Use the SDK signer, sign the exact tool and arguments of this call, sign a fresh intent for every call with a clock within 60 seconds of the server’s, and put on_behalf_of and session in the intent rather than only in headers. To check a signer without acting, send its header to POST /v1/intents/verify.

HTTP 403 · intent_invalid
{
"error": {
"type": "permission_error",
"code": "intent_invalid",
"message": "The signed intent's args_digest doesn't match the arguments sent. Sign the exact arguments you send, canonicalized with RFC 8785.",
"param": "args_digest",
"request_id": "req_01j9zr3m5k8q2w7x4t6v0b1c9d",
"doc_url": "https://docs.deedglass.com/errors/intent_invalid"
}
}

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) PermissionDeniedError with code === "intent_invalid"
Python (deedglass) deedglass.PermissionDeniedError with .code == "intent_invalid"