Skip to main content

Error Codes

All error responses use the same format:
Branch on code, not on error. code is the contract: it is never renamed or reused for a different meaning once shipped, so a client that switches on it keeps working. error is the human sentence and may be reworded at any time — matching it means a copy edit on our side silently breaks your integration.New codes may be added, so treat one you do not recognise as its HTTP status class rather than failing closed. Some responses carry no code at all: the admin debug routes, and anything served before codes shipped.Do not branch on the HTTP status alone either. It is overloaded: 404 is “no pool”, “no route” and the disguised admin gate; 409 is both a drifted firm quote and a simulation that failed on slippage, which need different recoveries. The code separates them.

Codes

On a /swap or /instructions rejection whose simulation failed, the result is attached at data.simulation. Its insufficientFunds and slippageExceeded booleans mirror SIM_INSUFFICIENT and SIM_SLIPPAGE.

HTTP status codes

API errors

Authentication errors

Quote errors (GET /api/v1/quote)

Swap errors (POST /api/v1/swap)

| simulation failed: insufficient funds | 400 | The wallet cannot fund this trade. Retrying will not change that | | simulation failed: slippage tolerance exceeded — re-quote and retry | 409 | The price moved between the quote and the build | | simulation failed: ... | 422 | The transaction would revert for some other reason; read data.simulation.logs |
A failed simulation is an error status. If POST /swap simulates the transaction and the simulation says it would fail, the response is a 400, 409 or 422 — never a 200 — and no transaction is returned, so there is nothing to accidentally sign.The simulation itself stays at data.simulation on the rejection, exactly where a successful response puts it, so code that already reads that field keeps working; it just has to stop treating 200 as the signal.Pass skipSimulation: true if you want the transaction regardless. Nothing simulates then, so nothing gates.
GET /quote will return an ExactOut quote over a Fluxbeam route, because the DEX restriction is enforced when the transaction is built, not when the route is priced. Handle the 400 at /swap or /instructions rather than assuming a successful quote implies an executable ExactOut swap.

Instructions errors (POST /api/v1/instructions)

Firm-quote errors (POST /api/v1/swap, POST /api/v1/instructions with quoteId)

See Firm quotes for how quoteId and firm work.

Simulation result errors

When skipSimulation is false, the swap response includes a simulation object:

On-chain errors

These surface after a signed transaction is submitted — in the transaction’s error and program logs, not in an HTTP response. They come from two sources: the Vulcx aggregator program itself, and the Solana runtime / SPL Token program underneath it.

Vulcx aggregator program errors

Anchor custom errors from program Vu1cUxynmbPUsFqVz51FJJ2y69vX2yrkTS13ajomd9D. In a failed transaction they appear as Custom(<code>) on the aggregator instruction and by name in the program logs. Administration and validation errors (6000 InvalidAmount, 6004 InvalidIndex, 6012–6015 InvalidFeeRecipient / FeeTooHigh / InvalidAdmin / ProtocolNotInitialized, 6018 InvalidStepCount) occur only on protocol-admin instructions or malformed hand-built transactions — not on engine-built swaps.

Solana runtime & SPL Token errors

These are not Vulcx program errors — they come from the network or the token program, so they carry no 6xxx code.
Last modified on September 20, 2026