Error Reference
ℹ️ Scope. This page documents the HTTP error envelope returned by the Behest admin/management APIs (
/auth/v1/*) and Kong-level rejections. For SDK-level typed errors (BehestAuthError,BehestQuotaError,BehestRateLimitError, etc.) thrown by@behest/client-tsv1.5 when consuming the inference/data-plane APIs, see Error handling.Every HTTP error documented here is what the SDK classifies under the hood — e.g., a 402 JSON body
{ "code": "quota_exceeded" }surfaces asBehestQuotaErrorwith.rawcarrying the body. Read both pages together.
Error Response Format
All behest-auth errors use a consistent JSON envelope:
{
error: string; // human-readable message
code?: string; // machine-readable code (present on errors that benefit from programmatic handling)
retryable?: boolean; // true if retrying the exact same request may succeed
// Additional context fields may appear for specific errors:
upgrade_url?: string;
}Example:
{
"error": "BYOAK requires a Pro subscription",
"code": "BYOAK_REQUIRES_PRO",
"upgrade_url": "/settings/billing"
}HTTP Status Codes
| Status | Meaning | When Behest uses it |
|---|---|---|
200 | OK | Successful GET, POST (mint), or state-changing action |
201 | Created | Tenant, project, or API key created |
204 | No Content | Successful DELETE or revoke |
302 | Found | Keep-alive endpoint redirect |
400 | Bad Request | Validation failure — request body is malformed or a field is invalid |
401 | Unauthorized | Missing or invalid credentials |
403 | Forbidden | Valid credentials but insufficient permissions |
404 | Not Found | Resource does not exist |
409 | Conflict | State conflict (e.g., tier limit reached, no draft to discard) |
422 | Unprocessable Entity | Request is well-formed but cannot be executed (e.g., model references provider with no key) |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
502 | Bad Gateway | Upstream service (Redis) failed during a critical operation |
Common Errors by Category
Authentication Errors (401)
Bearer token required
The Authorization header is missing or does not start with Bearer .
{ "error": "Bearer token required" }Fix: Include Authorization: Bearer <token> in all requests that require authentication.
Invalid API key format
The API key does not start with behest_sk_live_.
{ "error": "Invalid API key format" }Fix: Ensure you are using a Behest API key, not a JWT or other credential type.
Invalid API key
Key not found in the database. Either the key has never existed or the lookup hash does not match.
API key revoked
The key was revoked via the revoke or rotate endpoint.
Project is suspended
The project this key belongs to has been suspended. All API keys for suspended projects are automatically revoked on suspension.
{ "error": "Project is suspended" }Fix: Reactivate the project or create a new project.
Validation Errors (400)
Mint endpoint validation:
| Message | Cause |
|---|---|
"user_id must not be empty" | user_id is an empty string after trimming |
"user_id must be at most 255 characters" | user_id exceeds the maximum length |
"user_id cannot use a reserved identifier" | user_id is one of: dashboard-service, admin, system, internal, service, litellm, kong, behest |
"user_id cannot use the svc: prefix (reserved for service accounts)" | user_id starts with svc: |
"role is not a permitted role. Allowed: user, dashboard-service, admin" | Invalid role value |
"ttl must be at least 60 seconds" | ttl below minimum |
"ttl must be at most 86400 seconds" | ttl above maximum |
Settings endpoint validation:
| Message | Cause |
|---|---|
"system_prompt must be a string (max 32000 chars)" | Prompt too long |
"memory_window must be an integer 0-500" | Out of range |
"cors_origins must be an array of strings" | Wrong type |
"Invalid origin '...': must be scheme + host, no trailing slash" | CORS origin has a path or trailing slash |
"Cannot use wildcard CORS origin (*) with cors_allow_credentials=true" | Invalid CORS combination per RFC 6454 |
"rpm_limit must be an integer 1-10000" | Out of range |
"tokens_per_day must be an integer >= 1000" | Below minimum |
"pii_mode must be one of: disabled, shadow, enforce" | Invalid value |
"sentinel_blocklist must not exceed 200 terms" | Too many terms |
"retention_days must be an integer 1-365 or null" | Out of range |
"no fields to update" | PUT body has no recognized fields |
Permission Errors (403)
"Free plan is limited to 3 projects"
Free plan tenants can have at most 3 active projects.
{ "error": "Free plan is limited to 3 projects" }Fix: Suspend an existing project, or upgrade to Pro.
"BYOAK requires a Pro subscription"
{
"error": "BYOAK requires a Pro subscription",
"code": "BYOAK_REQUIRES_PRO",
"upgrade_url": "/settings/billing"
}Fix: Upgrade to the Pro plan.
"Forbidden"
The caller's tenant does not own the requested project (tier endpoints).
Conflict Errors (409)
"Maximum of 3 tiers per project"
{ "error": "Maximum of 3 tiers per project" }"Tier name already exists for this project"
Tier names must be unique within a project.
"No deployed settings to revert to. Deploy at least once before discarding draft."
{
"error": "No deployed settings to revert to. Deploy at least once before discarding draft.",
"code": "NO_DEPLOYED_SNAPSHOT"
}"No draft to publish"
{ "error": "No draft to publish", "code": "NO_DRAFT" }Unprocessable Entity Errors (422)
"provider key validation failed — the key was rejected by the provider API"
{
"error": "provider key validation failed — the key was rejected by the provider API",
"code": "KEY_VALIDATION_FAILED"
}Fix: Verify the key is active and has not been revoked in your provider dashboard.
"Your tenant has not configured a <Provider> API key."
{
"error": "Your tenant has not configured a OpenAI API key.",
"code": "PROVIDER_NOT_CONFIGURED"
}Fix: Add the provider key via PUT /auth/v1/tenants/:tenantId/providers/openai.
Rate Limit Errors (429)
Inference rate limit (Kong)
{
"error": "rate limit exceeded",
"message": "API rate limit exceeded"
}The Retry-After header (seconds until the current rate limit window resets) is included in the response. Implement exponential backoff and respect this header.
Provider key validation rate limit
{
"error": "Too many validation requests. Try again in a minute.",
"code": "RATE_LIMITED"
}Limit: 5 validation requests per minute per tenant.
Playground rate limit
{ "error": "Playground rate limit exceeded (50/hour)" }Bad Gateway Errors (502)
Redis sync failure on deploy
{
"error": "Settings saved but failed to sync to gateway. Please retry deploy.",
"code": "REDIS_SYNC_FAILED",
"retryable": true
}Settings were written to PostgreSQL successfully but the Redis sync failed. The database is consistent. Kong may be serving stale configuration. Retry the deploy endpoint — it will re-sync from the database.
Handling Errors in the SDK
async function mintTokenSafe(
apiKey: string,
userId: string
): Promise<string | null> {
const resp = await fetch("https://api.behest.app/auth/v1/auth/mint", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({ user_id: userId }),
});
if (resp.ok) {
const { access_token } = await resp.json();
return access_token;
}
const body = await resp.json().catch(() => ({ error: "unknown" }));
switch (resp.status) {
case 400:
// Validation error — log and fix the request
console.error("Mint validation error:", body.error);
return null;
case 401:
// Auth error — check key, check project status
if (body.error === "Project is suspended") {
throw new Error("Project suspended — contact Behest support");
}
throw new Error(`Authentication failed: ${body.error}`);
case 429: {
// Rate limited — respect Retry-After
const retryAfter = parseInt(resp.headers.get("Retry-After") ?? "60", 10);
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return mintTokenSafe(apiKey, userId); // retry once
}
case 500:
case 502:
if (body.retryable) {
// Transient error — retry with backoff
await new Promise((r) => setTimeout(r, 2000));
return mintTokenSafe(apiKey, userId);
}
throw new Error(`Server error: ${body.error}`);
default:
throw new Error(`Unexpected status ${resp.status}: ${body.error}`);
}
}Kong Gateway Errors
Errors returned by Kong before the request reaches behest-auth:
| Status | Cause |
|---|---|
401 | Missing Authorization header, expired JWT, invalid JWT signature |
403 | Kill switch active (global, tenant, or project) |
429 | Project RPM limit exceeded, per-user RPM limit exceeded, or daily token budget exhausted |
Kong errors use the format:
{
"error": "...",
"message": "..."
}The x-request-id header is always present on Kong responses and should be included in any bug reports or support requests.