Every error response follows the same format. Parse it once, handle it everywhere.
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Try again in 30 seconds.",
"request_id": "req_a1b2c3d4"
}
}
code — Machine-readable string. Use this in your error handling logic.
message — Human-readable explanation. Suitable for logging but not for display to end users.
request_id — Unique identifier that maps to the audit trail. Include it when contacting support.
Status codes
| Status | Code | When |
|---|
400 | BAD_REQUEST | Malformed JSON, missing required fields, invalid parameters |
401 | UNAUTHORIZED | Missing API key, invalid key, expired key, revoked key |
403 | FORBIDDEN | Key lacks required scope, feature not available on your plan |
404 | NOT_FOUND | Endpoint doesn’t exist, resource not found |
429 | RATE_LIMITED | Too many requests. Respect the Retry-After header |
500 | INTERNAL_ERROR | Server error. These are our fault — contact support with the request_id |
502 | BAD_GATEWAY | The upstream AI provider returned an error |
503 | SERVICE_UNAVAILABLE | Gateway overloaded, coordinator unreachable, maintenance |
Handling errors in code
const response = await fetch("https://gateway.takumo.io/v1/tokenize", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ content: sourceCode, filename: "config.ts" })
});
if (!response.ok) {
const { error } = await response.json();
switch (error.code) {
case "UNAUTHORIZED":
// Key is invalid or revoked. Check your configuration.
break;
case "RATE_LIMITED":
const retryAfter = Number(response.headers.get("Retry-After"));
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
// Retry the request
break;
case "BAD_GATEWAY":
// AI provider issue, not Takumo. Check provider status page.
break;
default:
console.error(`Takumo error: ${error.code} - ${error.message}`);
}
throw new Error(`${error.code}: ${error.message} (${error.request_id})`);
}
Common error scenarios
400 BAD_REQUEST
{
"error": {
"code": "BAD_REQUEST",
"message": "Missing required field: content",
"request_id": "req_x1y2z3"
}
}
Check that your request body is valid JSON with all required fields.
401 UNAUTHORIZED
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired API key",
"request_id": "req_x1y2z3"
}
}
Verify your API key is correct and hasn’t been revoked. Keys use the tk_live_ or tk_test_ prefix.
429 RATE_LIMITED
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710360000
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Try again in 30 seconds.",
"request_id": "req_x1y2z3"
}
}
Wait for the number of seconds in Retry-After. Do not retry in a tight loop. See Rate Limits for per-plan limits.
502 BAD_GATEWAY
{
"error": {
"code": "BAD_GATEWAY",
"message": "Upstream provider returned 500",
"request_id": "req_x1y2z3"
}
}
This means the AI provider (Anthropic, OpenAI, etc.) had an error. Check the provider’s status page. This is not a Takumo issue.
Always include the request_id when contacting support. It maps directly to the audit trail and helps us diagnose the issue quickly.