Skip to main content
Every error thrown by Earn is a KitError carrying structured fields. Read those fields to decide how to handle each error, instead of parsing error strings. Errors surface from every Earn operation, including deposit, withdraw, and preview quotes.

KitError fields

Check code or name for specific handling, type for handling a whole category, and recoverability to decide whether to retry.

Error types

Common Earn error codes

Check these codes for specific handling. Reference the JavaScript constant as EarnError.<NAME>.code. The underlying error.name includes the EARN_ prefix.

Helper functions

Import error utilities from @circle-fin/app-kit (or @circle-fin/earn-kit if you’re using only the standalone Earn Kit):
TypeScript

Handling errors

This example shows a complete error handling pattern for a deposit, including a check for a specific error code:
TypeScript

Resume a failed operation with kit.earn.retry

Deposits and withdrawals run through multiple phases (fetchParams, approve, execute). When a failure has recoverability === 'RESUMABLE', the operation stopped mid-flow with some phases already complete. Call kit.earn.retry(error) to resume from the failed step instead of restarting from scratch. Reuse the caught KitError. It carries the original inputs and step progress.
TypeScript
Use isRetryableError for errors where the full operation can be retried from the beginning. Use isResumableError when the operation should continue from the failed step. Retry re-fetches execution parameters and might re-submit the execute transaction. Treat it as best-effort recovery. If a prior attempt broadcast the execute transaction but failed before observing the receipt, that transaction might still be in flight.

Observe step events

App Kit forwards Earn step events to handlers registered on the kit. Use them to render progress or log which phase a failure occurred in. Register a handler with kit.on(); detach it with kit.off().
TypeScript
Available action names: earn.approve, earn.deposit, earn.withdraw, earn.crossChainDeposit, earn.crossChainDepositStatus. Each payload carries the operation, method (phase), and values for that step.

Partial success in getVaults

getVaults uses partial success semantics: a network, auth, or service failure throws a KitError, but a single vault that can’t be resolved is returned in the errors array instead of throwing. One bad vault doesn’t fail the whole batch.
TypeScript

Errors from your wallet adapter

deposit and withdraw submit transactions through the wallet adapter you supply (for example, @circle-fin/adapter-viem-v2). Wallet and RPC failures during execution surface as KitErrors with these type categories:
  • BALANCE (codes in the 9000s): insufficient token balance, gas, or allowance. FATAL.
  • ONCHAIN (codes in the 5000s): simulation or execution failures. FATAL.
  • RPC (codes in the 4000s): RPC endpoint or nonce issues. RETRYABLE.
  • INPUT_USER_CANCELLED (1099): user rejected the wallet prompt. FATAL.
Handle them by type and recoverability rather than enumerating every code.

Common error scenarios

Rate limiting

Rate limit responses are RATE_LIMIT errors with RETRYABLE recoverability. Apply the backoff-and-retry pattern from the deposit example. Earn rate limits are enforced at multiple layers; all relevant layers must be satisfied for a request to succeed. In permissionless mode (no API key), only the per-IP and global limits apply. Using an API key adds the per-entity limit, which gives more headroom for server-side integrations sending traffic from multiple IPs. To avoid hitting rate limits in production:
  • Obtain a Circle API key from the Circle Console and pass it on each operation as config.apiKey. For a restricted key, select the “App Kits” product permission when creating the key.
  • Cache getVaults results. Vault metadata changes infrequently. Refreshing every 30 to 60 seconds is sufficient.
  • Batch vault address lookups. Pass up to 20 addresses in a single getVaults call instead of calling it once per address.