Error response format
All errors follow the same envelope:{
"success": false,
"error": "descriptive error message"
}
Common errors
| HTTP Status | Error | Cause | Fix |
|---|---|---|---|
401 | missing api key | No Authorization: Bearer header or ?key= param | Add your API key — see Authentication |
403 | invalid api key | Key is invalid, disabled, or revoked | Request or rotate a key |
400 | invalid inputMint | Mint address is not valid base58 | Check the token mint address |
400 | invalid amount | Amount is not a valid number or is zero | Use string representation of the amount in smallest units |
400 | invalid swapMode | Must be ExactIn or ExactOut | Check the swapMode parameter |
404 | no route found | No liquidity path exists for this pair/amount | Try a smaller amount, different slippage, or check if the token is supported |
404 | no pool found | No pool exists for one of the hops | The token may not have any listed pools |
404 | no route found: insufficient liquidity | Pools exist but don’t have enough liquidity for this amount | Reduce the swap amount |
400 | multi-hop ExactOut is not supported on-chain; ... | ExactOut works on a single hop only | Use the ExactIn-with-buffer pattern in the message |
400 | ExactOut is only supported on Vortex pools; ... | Route crosses Fluxbeam or Moonit, which have no exact-out CPI | Re-quote as ExactIn, or excludeDexes |
422 | the best route needs more accounts than fit ... | Route found but too large for one transaction | Constrain with maxHops / excludeDexes, or split the trade |
429 | rate limit exceeded | Too many requests | Back off and retry with exponential delay |
A failed simulation is not an error status.
POST /swap returns 200 with simulation.success: false and the failure detail in the body — check that field, not the HTTP status.Handling errors in code
response=$(curl -s -w "\n%{http_code}" "https://api.vulcx.xyz/api/v1/quote?inputMint=INVALID&outputMint=uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG&amount=1000000000&swapMode=ExactIn" \
-H "Authorization: Bearer $VULCX_KEY")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -1)
if [ "$http_code" != "200" ]; then
echo "Error ($http_code): $body"
fi
const response = await fetch(
"https://api.vulcx.xyz/api/v1/quote?" +
new URLSearchParams({
inputMint: "So11111111111111111111111111111111111111112",
outputMint: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
amount: "1000000000",
swapMode: "ExactIn",
}),
{ headers: { Authorization: `Bearer ${process.env.VULCX_KEY}` } }
);
const result = await response.json();
if (!result.success) {
const err = result.error ?? "";
// Match by PREFIX, not equality. Most messages carry detail after the stem —
// "insufficient liquidity" arrives as "no route found: insufficient liquidity",
// so an === comparison silently never matches.
if (err === "missing api key" || err === "invalid api key") {
console.log("Check your Authorization header / API key.");
} else if (err.startsWith("no route found: insufficient liquidity")) {
console.log("Not enough liquidity. Reduce the amount.");
} else if (err.startsWith("no route found")) {
console.log("No swap route available. Try a smaller amount.");
} else if (err.startsWith("multi-hop ExactOut")) {
console.log("ExactOut is single-hop only — use ExactIn with a buffer.");
} else if (err.startsWith("ExactOut is only supported on Vortex")) {
console.log("Re-quote as ExactIn, or excludeDexes to force a Valiant route.");
} else {
console.error(`API error: ${err}`);
}
}
import os, requests
resp = requests.get(
"https://api.vulcx.xyz/api/v1/quote",
params={
"inputMint": "So11111111111111111111111111111111111111112",
"outputMint": "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
"amount": "1000000000",
"swapMode": "ExactIn",
},
headers={"Authorization": f"Bearer {os.environ['VULCX_KEY']}"},
)
result = resp.json()
if not result["success"]:
error = result["error"]
if error == "no route found":
print("No swap route available. Try a smaller amount.")
elif error == "insufficient liquidity":
print("Not enough liquidity. Reduce the amount.")
else:
print(f"API error: {error}")
Simulation errors
WhenskipSimulation is false (default), the swap endpoint simulates the transaction before returning it. Check the simulation field in the response:
{
"simulation": {
"success": false,
"error": "insufficient funds",
"insufficientFunds": true,
"slippageExceeded": false,
"computeUnitsConsumed": 0,
"logs": ["Program log: Error: insufficient lamports"]
}
}
| Field | Meaning |
|---|---|
insufficientFunds | Wallet doesn’t have enough tokens for the swap + transaction fees |
slippageExceeded | Price moved beyond the slippage tolerance between quote and transaction build |
On-chain transaction errors
Even after a successful simulation, the transaction can fail on-chain if conditions change between simulation and confirmation.| Error | Cause | Fix |
|---|---|---|
SlippageExceeded | Price moved after submission | Increase slippageBps or retry quickly |
InsufficientFunds | Balance changed between simulation and execution | Re-check balance before submitting |
BlockhashExpired | Transaction took too long to confirm | Rebuild the transaction and resubmit |
Retry strategy
| Error category | Action |
|---|---|
| Quote failures (404) | Retry after 1-2 seconds. Liquidity can appear as pools rebalance. |
| Rate limits (429) | Exponential backoff: 1s, 2s, 4s, 8s. Max 3 retries. |
| Simulation failures (500) | Re-fetch a fresh quote and rebuild. Don’t retry the same transaction. |
| On-chain failures | Get a new quote (prices have likely changed) and rebuild from scratch. |