InterceptDocumentation
Docs/Developers/Error Handling
Reference (illustrative)

Error Handling

Every planned reason code with its layer and recommended agent response, plus transport errors, retries, idempotency keys and the fail-closed default.

An Intercept integration can fail in two different ways, and they need different handling. A decision is Intercept working correctly and telling you not to proceed. A transport error is Intercept, the network or your own request failing before a decision is reached. Confusing the two is the most common way to build an integration that fails open.

Decisions versus transport errors

Decision Transport error
HTTP status 200 4xx, 5xx, timeout, connection failure
Body Decision object with reasons Error object or nothing
Meaning Intercept evaluated the transaction No evaluation happened
Retry? No; the same transaction will get the same answer Sometimes; see below
Default handling Respect the decision Fail closed: treat as blocked

A blocked decision is not an exception. The SDK is designed to return it as a normal value and reserve thrown errors for transport failures, misuse (such as calling execute on a non-approved result) and invalid configuration.

Reason codes

Code Layer Meaning Recommended agent behavior
RISK_MAX_TX_SIZE risk Transaction value exceeds maxTransactionUsd Split into smaller transactions only if the strategy allows; do not loop to evade the limit
RISK_DAILY_LIMIT risk Rolling 24h outflow would exceed dailySpendLimitUsd Stop new outflows until the window rolls; alert the operator
RISK_MAX_LEVERAGE risk Resulting leverage exceeds maxLeverage Reduce size or add collateral, then re-evaluate
RISK_POSITION_SIZE risk Position would exceed maxPositionPct of portfolio Reduce size
RISK_DRAWDOWN risk Drawdown in window exceeds maxDrawdownPct Stop increasing exposure; expect circuit breakers
RISK_SLIPPAGE risk Expected slippage exceeds maxSlippageBps Re-quote, reduce size or wait for liquidity
RISK_LIQUIDITY risk A routed pool is below minPoolLiquidityUsd Choose a different route
SEC_PROTOCOL_NOT_ALLOWED security Transaction invokes a program not in allowedProtocols Do not retry; a human must change the policy
SEC_BLOCKED_ADDRESS security Transaction touches an address in blockedAddresses Do not retry; treat as a security event
SEC_SIMULATION_FAILED security Simulation failed or was unavailable under simulation: "required" Rebuild with a fresh blockhash and re-evaluate once; then stop
SEC_UNLIMITED_APPROVAL security Transaction grants an unbounded token delegate Rebuild with an exact approval amount
SEC_AUTHORITY_CHANGE security Transaction changes an account, mint or upgrade authority Do not retry; requires human review
SEC_PROMPT_INJECTION_SUSPECTED security Stated intent does not match simulated effects Halt the current task, discard untrusted inputs, alert the operator
NET_FLAGGED_ADDRESS network An address, authority or mint is flagged in the Threat Registry Do not retry; see Threat Intelligence
NET_FLAGGED_PROGRAM network A program is flagged in the Threat Registry Do not retry
SYS_PAUSED system Agent is paused manually, by guardian or by circuit breaker Stop; wait for agent.resumed
SYS_TIMEOUT system Evaluation did not complete within timeoutMs Fail closed; retry with the same idempotency key
SYS_POLICY_INVALID system Active policy is missing or failed validation Stop; fix and republish the policy

The NET_* codes depend on the proposed Intercept Network, which is planned for a later phase than the other layers.

An agent should never treat a security or network code as a puzzle to route around. Retrying a blocked transaction with small changes until it passes is the behavior Intercept exists to stop. In advisory mode, nothing technically prevents it, which is why blocking only works if the integration is enforced.

Fail-closed default

When the SDK cannot obtain a decision, it is designed to return a synthetic blocked result with SYS_TIMEOUT rather than throw or approve. This is the failMode: "closed" default.

TypeScript
const result = await intercept.evaluate(transaction, { agentId: "agent_7f3c" });
// On timeout or 5xx, result.decision === "blocked" and
// result.reasons[0].code === "SYS_TIMEOUT"

failMode: "open" exists for advisory-mode testing only. It is designed to be rejected when the policy mode is enforced. In enforced mode there is no fail-open option: if Intercept cannot co-sign, the transaction cannot execute.

Retries

Condition Retry? How
200 with any decision No Re-evaluate only after changing the transaction
400, 401, 403, 404, 422 No Fix the request, key or policy
409 idempotency conflict No Use a new key for a different request
429 Yes Wait for Retry-After
5xx, timeout, connection reset Yes Exponential backoff with jitter, same idempotency key

Solana transactions also expire. A retry loop that outlasts the blockhash's validity, roughly 150 slots, will produce SEC_SIMULATION_FAILED. Rebuild with a fresh blockhash, or use a durable nonce, and evaluate again with a new idempotency key.

Idempotency keys

Send an Idempotency-Key header (or idempotencyKey in the SDK context) on every POST and PUT. If a request is retried with the same key and body, Intercept is designed to return the original response instead of evaluating or executing twice.

This matters most for execute. If the connection drops after Intercept co-signed and submitted, a naive retry could appear to fail or, worse, submit a second transaction. With the same key, the retry returns the original signature.

  • Generate one key per logical operation, such as a UUID, not per HTTP attempt.
  • Reusing a key with a different body returns 409.
  • Keys are designed to be retained for 24 hours.
© InterceptDocumentation describes planned functionality unless stated otherwise.