API Errors
Error responses from the Turbine.cash API
API Errors
Section titled “API Errors”Error responses from the Turbine.cash relayer and indexer API.
HTTP Status Codes
Section titled “HTTP Status Codes”| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid input |
| 401 | Unauthorized - Invalid/expired token |
| 403 | Forbidden - OFAC or permission denied |
| 404 | Not Found - Resource doesn’t exist |
| 429 | Too Many Requests - Rate limited |
| 500 | Internal Server Error |
| 503 | Service Unavailable |
Error Response Format
Section titled “Error Response Format”Most errors return JSON:
{ "status": 400, "error": "ErrorCode", "message": "Human-readable description"}Or for relay endpoints:
{ "status": 400, "error": "NullifierAlreadySpent"}Authentication Errors
Section titled “Authentication Errors”Invalid Signature
Section titled “Invalid Signature”{ "status": 400, "error": "InvalidSignature", "message": "Signature does not match wallet and message"}Causes:
- Wrong wallet signed the message
- Message was modified after signing
- Signature encoding is incorrect
Solution: Ensure the signature is for the exact timestamp message.
Token Expired
Section titled “Token Expired”{ "status": 401, "error": "TokenExpired", "message": "Auth token has expired"}Solution: Re-authenticate with a fresh signature.
Invalid Token
Section titled “Invalid Token”{ "status": 401, "error": "InvalidToken", "message": "Auth token is invalid or malformed"}Solution: Check token format and re-authenticate.
Relay Errors
Section titled “Relay Errors”NullifierAlreadySpent
Section titled “NullifierAlreadySpent”{ "status": 400, "error": "NullifierAlreadySpent"}Already withdrawn. Check local records.
InvalidProof
Section titled “InvalidProof”{ "status": 400, "error": "InvalidProof"}ZK proof failed verification. Regenerate with correct inputs.
InvalidRoot
Section titled “InvalidRoot”{ "status": 400, "error": "InvalidRoot"}Merkle root is stale. Refetch and regenerate proof.
OFACCheckFailed
Section titled “OFACCheckFailed”{ "status": 403, "error": "OFACCheckFailed"}Recipient address failed compliance check.
RelayFailed
Section titled “RelayFailed”{ "status": 500, "error": "RelayFailed", "message": "Transaction submission failed: ..."}Relay couldn’t submit transaction. May be temporary - retry.
Swap Errors
Section titled “Swap Errors”SwapFailed
Section titled “SwapFailed”{ "status": 400, "error": "SwapFailed", "message": "Jupiter swap failed: insufficient liquidity"}Jupiter couldn’t execute swap. Try different amount or route.
SlippageExceeded
Section titled “SlippageExceeded”{ "status": 400, "error": "SlippageExceeded", "message": "Price moved beyond slippage tolerance"}Increase slippage or retry when markets stabilize.
Rate Limit Errors
Section titled “Rate Limit Errors”{ "status": 429, "error": "RateLimited", "message": "Too many requests. Retry after 60 seconds"}Wait before retrying. Consider implementing backoff.
Error Handling Best Practices
Section titled “Error Handling Best Practices”interface ApiError { status: number; error: string; message?: string;}
async function callApi(endpoint: string, options: RequestInit): Promise<any> { const response = await fetch(endpoint, options);
if (!response.ok) { let error: ApiError;
try { error = await response.json(); } catch { error = { status: response.status, error: 'UnknownError', message: await response.text(), }; }
throw new ApiException(error); }
return response.json();}
class ApiException extends Error { constructor(public error: ApiError) { super(error.message || error.error); }
isRetryable(): boolean { // Retry on rate limits and server errors return this.error.status === 429 || this.error.status >= 500; }
isAuthError(): boolean { return this.error.status === 401; }}
// Usage with retry logicasync function relayWithRetry(params: RelayParams, maxRetries: number = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { return await callApi('/relay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); } catch (err) { if (err instanceof ApiException) { if (err.isAuthError()) { // Re-authenticate await reAuthenticate(); continue; }
if (err.isRetryable() && attempt < maxRetries - 1) { await sleep(1000 * (attempt + 1)); // Exponential backoff continue; } }
throw err; } }}Debugging API Errors
Section titled “Debugging API Errors”-
Check request format:
console.log('Request:', JSON.stringify(body, null, 2)); -
Verify auth token:
const isValid = await fetch(`/is_logged/${token}`);console.log('Token valid:', isValid.ok); -
Check API health:
const health = await fetch('/health');console.log('API healthy:', health.ok); -
Review response headers:
response.headers.forEach((value, key) => {console.log(`${key}: ${value}`);});