Skip to content
JAOT

Error Reference

Complete reference for all error responses returned by the JAOT API.

Error Response Schema

All API errors return a consistent JSON structure:

{
  "detail": "Human-readable error message",
  "error_code": "ERROR_CODE",
  "status_code": 400
}
FieldTypeDescription
detailstringHuman-readable description of the error
error_codestringMachine-readable error code for programmatic handling
status_codeintHTTP status code

Validation errors (422) include additional detail about which fields failed:

{
  "detail": [
    {
      "loc": ["body", "num_variables"],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ],
  "status_code": 422
}

HTTP Status Codes

CodeNameDescription
400Bad RequestInvalid input, missing required fields, or malformed request body
401UnauthorizedAPI key is invalid, expired, or missing from the request
402Payment RequiredInsufficient credits to perform the operation
403ForbiddenValid credentials but insufficient permissions (not admin, wrong organization)
404Not FoundThe requested resource does not exist
409ConflictResource already exists (e.g., duplicate API key name)
422Unprocessable EntityRequest body fails validation (Pydantic schema errors)
429Too Many RequestsRate limit exceeded -- wait and retry
500Internal Server ErrorUnexpected server failure
503Service UnavailableSolver or worker is temporarily unavailable

Common Errors with Fixes

Error MessageCauseFix
"Invalid API key"API key has been revoked or is mistypedCreate a new API key in the dashboard
"Not authenticated"No Authorization header in requestAdd Authorization: Bearer <api_key> header
"Insufficient credits"Organization credit balance is too lowPurchase credits or use the credit calculator to estimate costs
"Model not found"Wrong model ID or model not activated for your orgVerify the model ID with list_models() and activate it first
"Infeasible problem"The constraints have no valid solutionReview constraints for conflicts -- try relaxing bounds
"Solver timeout"time_limit is too short for problem complexityIncrease time_limit or simplify the problem
"Rate limit exceeded"Too many requests in the current windowWait for retry_after seconds, then retry
"Validation error"Request payload does not match expected schemaCheck field names, types, and required parameters
"Server at capacity"All solver workers are busyUse the async solve endpoint (async_mode=True)

Retry Strategy

Some errors are transient and can be resolved by retrying. Others indicate problems with the request itself and should not be retried.

Retryable Errors

CodeWhen to Retry
429After the retry_after duration from the response
503After a short delay (solver temporarily at capacity)
500After a short delay (may be a transient server issue)

Non-Retryable Errors

CodeAction Required
400Fix the request payload
401Check your API key
402Purchase more credits
403Check your permissions
404Verify the resource ID
422Fix the validation errors

Warning: Never retry 400, 401, 403, or 422 errors. These indicate problems with the request that will not resolve on their own.

Exponential Backoff Example

import time
import httpx
 
API_KEY = "ok_live_..."
BASE_URL = "https://api.jaot.io"
 
def solve_with_retry(payload, max_retries=3):
    """Solve with retry logic and exponential backoff."""
    for attempt in range(max_retries + 1):
        response = httpx.post(
            f"{BASE_URL}/api/v2/solve",
            headers={"Authorization": f"Bearer {API_KEY}"},
            json=payload,
        )
        if response.status_code == 429:
            if attempt == max_retries:
                response.raise_for_status()
            retry_after = response.json().get("retry_after", 2 ** attempt)
            print(f"Rate limited, waiting {retry_after}s...")
            time.sleep(retry_after)
            continue
        if response.status_code >= 500:
            if attempt == max_retries:
                response.raise_for_status()
            wait = 2 ** attempt
            print(f"Server error, retrying in {wait}s...")
            time.sleep(wait)
            continue
        response.raise_for_status()
        return response.json()
 
 
# Usage
result = solve_with_retry({"variables": [...], "constraints": [...]})

Tip: Implement exponential backoff for 429 and 5xx errors. Non-retryable errors (400, 401, 403, 422) indicate problems with the request itself.