The SDK uses typed error classes so you can catch and handle each scenario precisely. Every error extends MandateError, which itself extends the native Error.
The base class for all SDK errors. You receive this for generic API failures that don’t fall into a more specific category.
Property
Type
Description
message
string
Human-readable error description
statusCode
number
HTTP status code from the API
blockReason
string | undefined
Machine-readable reason code, if available
When it fires: Any non-OK API response that isn’t a 403 circuit breaker, 422 policy block, or 202 approval redirect. Common cases: network errors, 500 server errors, malformed requests.Recovery: Check statusCode to decide whether to retry. 5xx errors are transient and safe to retry with backoff. 4xx errors indicate a client-side problem.
Thrown when a transaction violates one or more policy rules: spend limits, allowlists, time schedules, function selectors, or other constraints configured in the dashboard.
User-facing decline message set by the policy owner
When it fires: The policy engine evaluates the transaction against the agent’s active policy and finds a violation. This covers per-transaction limits, daily/monthly quotas, address allowlists, time-of-day schedules, and function selector restrictions.Recovery: Display declineMessage to the end user if present. Adjust the transaction parameters (lower the amount, use an allowed address) or ask the agent owner to update the policy in the dashboard.
Copy
Ask AI
try { await wallet.transfer(to, amount, tokenAddress);} catch (err) { if (err instanceof PolicyBlockedError) { console.log(`Blocked: ${err.blockReason}`); if (err.declineMessage) { console.log(`Reason: ${err.declineMessage}`); } if (err.detail) { console.log(`Detail: ${err.detail}`); } }}
PolicyBlockedError is also exported as MandateBlockedError for backward compatibility. They are the same class.
Thrown when the agent’s circuit breaker is active. This is an emergency stop: all transactions are blocked until the owner resets it.
Property
Type
Description
message
string
"Circuit breaker is active. All transactions are blocked."
statusCode
number
Always 403
blockReason
string
Always "circuit_breaker_active"
When it fires: The circuit breaker trips automatically when the envelope verifier detects that a broadcast transaction does not match the parameters that were validated. An owner can also trigger it manually from the dashboard.Recovery: No programmatic fix exists. The agent owner must investigate and reset the circuit breaker in the Mandate dashboard. Your code should log the error and halt further transaction attempts.
Copy
Ask AI
try { await wallet.transfer(to, amount, tokenAddress);} catch (err) { if (err instanceof CircuitBreakerError) { console.error('EMERGENCY: Circuit breaker active. Halting all transactions.'); // Notify ops team, stop the agent loop }}
Thrown when a transaction passes policy checks but requires explicit human approval before it can proceed.
Property
Type
Description
message
string
"Transaction requires human approval. Poll /status until approved."
statusCode
number
Always 202
blockReason
string
Always "approval_required"
intentId
string
The intent ID to poll for a decision
approvalId
string
The approval request ID
approvalReason
string | undefined
Why approval is needed (e.g. "amount_above_threshold")
When it fires: The policy includes an approval rule, and the transaction matches that rule’s criteria. The intent enters approval_pending state and waits for the owner to approve or reject via the dashboard.Recovery: Call client.waitForApproval(intentId) to poll until the owner makes a decision. The method resolves when approved, or throws if rejected or expired. You can also use MandateWallet.sendTransactionWithApproval() which handles this flow automatically.
Copy
Ask AI
try { await client.validate(payload);} catch (err) { if (err instanceof ApprovalRequiredError) { console.log(`Awaiting approval: ${err.approvalId}`); console.log(`Reason: ${err.approvalReason ?? 'policy rule'}`); const status = await client.waitForApproval(err.intentId, { timeoutMs: 3600_000, // 1 hour (matches server TTL) onPoll: (s) => console.log(`Status: ${s.status}`), }); console.log(`Approved. Proceed with intent ${status.intentId}`); }}
When it fires: Before policy evaluation, Mandate runs the destination address through its risk scanner. If the address is associated with known exploits, sanctions, or other critical risks, this error fires.Recovery: Verify the destination address. If you believe it is a false positive, contact the Mandate risk team. Do not attempt to bypass this check.
Copy
Ask AI
try { await wallet.transfer(to, amount, tokenAddress);} catch (err) { if (err instanceof RiskBlockedError) { console.error(`Risky address: ${err.blockReason}`); // Do not retry with the same address }}