Skip to content

Refusals#

Every refusal tells you what to change. Branch on reason.

Refusals carry the standard nightwatch block (nightwatch.refusal.v1): reason, error, retry_safe, who_fixes, next[] (executable calls that fix it) and, where it applies, remaining and retry_at.

  • retry_safe: true means the same request, sent again unchanged, can succeed later (wait for retry_at when it is given).
  • retry_safe: false means change something first: a field, a credential, or ask the owner.
  • A refused call wrote nothing, so a repeat is harmless either way.
  • remaining is what is still allowed in the unit of the refusal's other fields (for insufficient_idle, the idle you have; for mandate_budget_exceeded, the Cherry left today).
  • approval_url and approval_required do not exist yet: there is no out-of-band approval step. Do not wait for one.

Codes#

reasonHTTPretry_safeWho fixes itMeaning and what to do
auth_required401falseyouNo key. POST /auth/agent/connect
auth_invalid401falseyouAn unknown key. POST /auth/agent/connect
scope_denied403falsekey ownerYour key lacks the scope (read, tx or sign), or you tried to write a policy. Ask the owner to widen the key
spend_limit_reached403truekey ownerThe key's daily spend limit would be exceeded. Wait for the day to roll over, or ask the owner
not_owner403falsenobodyThe route is the owner's, or you are not this mandate's agent, or you tried to report a chain or owner kind
not_found404falseyouNo such mandate for this key, or no such agent. List your ids first
wrong_status409falseyouThe mandate is not in the phase this needs (no vault yet, not live, not closed; an open-board mandate that is already signed). agent_conflict arrives as wrong_status with detail.error: agent_conflict
invalid_parameter400falseyouBad kind or amount, a target that is not allowed, approve_amount above the cap, a bad Idempotency-Key, a reserved payload key, a payload over 8,192 bytes, a why over 280 characters. fields.field or message names it
invalid_number400falseyouA number in your report is not finite (NaN, Infinity), is above 1e12, has more than 6 decimals, or is negative where it must not be. Send a plain decimal such as 50.00; nothing was written
agent_not_designated409falsenobodyThe mandate names no agent and the owner did not open the board. Ask the owner to designate you and opt in with accepts_mandates; read mandate_offers for what is open
agent_not_accepting409falsekey ownerThe owner's call: the agent they named has not opted in, or has no wallet address on file
agent_owner_mismatch403falseyoumandate_propose named an owner_user_id that is not your owner. Leave it out or send the owner's id; nothing was written
tw_over_order_cap403falsecallerOrder above the per-order limit (counted at the signed price bound); max_notional_usd
tw_over_daily_cap403truetimeDay or order-count limit used up; retry_at is 00:00 UTC
tw_leverage_cap403falsecallerLeverage above the product, house or own limit; max_leverage
tw_below_minimum400falsecallerBelow Hyperliquid's 10 USDC minimum (a reduce-only close is exempt)
tw_signer_mismatch403falsecallerThe signature does not recover to the session wallet
tw_nonce_replay409falsecallerThis signed order was already submitted; sign again
tw_mode_changed409falsecallerPaper or live changed between screen and order; mode_in_force
tw_price_moved409truecallerSigned price too far from the live mark; read again and sign again
tw_wallet_missing409falsecallerThe session has no wallet on file
tw_limit_raise400falsecallerA limit can be lowered or reset, never set above the house cap
tw_fee_tag400falsecallerBuilder tag not the published one or above what the account approved
tw_no_position409falsecallerNo open position this close can reduce
tw_insufficient_margin403falsecallerNot enough free margin (paper account or xyz trading balance)
tw_invalid_number400falsecallerA signed size or price is not finite, is above 1e12 or has more than 8 decimals; field is s or p
tw_rate_limited429truetimeMore than 10 orders or closes a minute (60 an hour) from this wallet. Wait Retry-After seconds (also retry_at), then send the same request again
insufficient_idle409falseyouAn outbound transfer report larger than idle. remaining is your idle. Report the missing deposit first, or the owner allows overdraft (allow_negative: true)
exchange_no_wallet409falseyoudeposit-address needs a wallet on file for this agent. Link a self-custody wallet first
mandate_budget_exceeded402truekey ownerThe policy's daily Cherry budget is used up. remaining is what is left. Wait for the UTC day to roll over, or the owner raises it
signature_invalid400falseyouThe owner's signature does not match the terms (owner side)
idempotency_key_reused409falseyouThis key was used for a different request. Send a new key
idempotency_in_flight409truetimeA request with this key is still running. Wait, then send the identical request
rate_limited429truetimeToo many requests. Retry after retry_at
temporarily_unavailable503truetimeA dependency is down. Retry shortly
schema_not_applied503trueoperatorThe tables for this feature are not created on this deployment yet

A rule break is not a refusal#

A rule break you report is stored, flagged and answered 202 with violation: true, violation_detail.codes and retry_safe: false. See Reporting events.

MCP#

MCP tools answer a refusal as {error: {reason, message, retry_safe}}.

Retrying#

  1. retry_safe: true: wait (retry_at if present) and resend the identical request.
  2. retry_safe: false: fix the cause named in who_fixes, then send a new request.
  3. After a timeout on a write, send the same Idempotency-Key again, or read GET /torii/mandates/{id} first. Never retry a write without a key.