Skip to main content

Overview

NanoGPT APIs return standard HTTP status codes. Many endpoints also follow OpenAI- or Anthropic-compatible error shapes so you can reuse existing SDK error handling. If you contact support about an API error, include the X-Request-ID response header (when present).

Error Response Formats

NanoGPT has a few common error envelopes depending on the API surface.

OpenAI-compatible (most /api/v1/* endpoints)

Used by endpoints like:
  • POST /api/v1/chat/completions
  • POST /api/v1/responses
  • POST /api/v1/embeddings
  • GET /api/v1/models
{
  "error": {
    "message": "Human-readable error message",
    "type": "invalid_request_error",
    "code": "missing_required_parameter",
    "param": "model"
  }
}
Fields:
  • error.message: human-readable
  • error.type: high-level category (see Error Types)
  • error.code: optional machine-readable code (see Error Codes)
  • error.param: optional name of the request field that caused the error

Anthropic-compatible (POST /api/v1/messages)

The Messages API uses the Anthropic-style wrapper:
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "max_tokens is required",
    "param": "max_tokens"
  }
}

Legacy / simple format (some /api/* endpoints)

Some older endpoints return a simpler body:
{ "error": "Insufficient balance", "status": 402 }
Some responses also include a structured object and convenience fields (for example, requiredBalance on 402).

Status Codes

This table covers the most common HTTP error statuses you may encounter.
StatusMeaningTypical client action
400Invalid request / validation failedFix the request, then retry
401Missing/invalid API keyDo not retry until credentials are fixed
402Insufficient balanceAdd funds or disable paid enhancements, then retry
403Authenticated but not permittedChoose an allowed model/feature or change permissions
404Resource not foundCheck the model/resource ID
408 / 504TimeoutRetry with backoff
409ConflictResolve state (duplicate/redeemed/already processed)
413Payload too largeReduce payload size and retry
429Rate limitedWait (use Retry-After if present), then retry. This can be a per-second throughput limit or a per-key daily limit.
500Server errorRetry with backoff
503Temporarily unavailableRetry with backoff; consider changing model if persistent
Notes:
  • Some endpoints include convenience fields like status in the JSON body mirroring the HTTP status code.
  • Some error responses include Retry-After (seconds) for 429.

Error Types

Depending on the endpoint, you may see different type strings. Common values include:
  • invalid_request_error (400)
  • authentication_error (401)
  • permission_denied_error or permission_error (403)
  • not_found_error (404)
  • rate_limit_error (429)
  • server_error, service_unavailable, or api_error (500/503)

Error Codes

Not every error includes a code. When present, codes are useful for programmatic handling. Common codes include:

Request validation

  • missing_required_parameter
  • invalid_parameter_value
  • invalid_json
  • invalid_json_schema
  • tool_choice_unsupported
  • image_input_not_supported
  • conflicting_moderation_model
  • inline_moderation_requires_api_key
  • empty_moderation_input
  • unsupported_moderation_input
  • unsupported_input_modality
  • unsupported_batch_input

Content and context

  • content_policy_violation
  • context_length_exceeded
  • empty_response

Model and routing

  • model_not_found
  • model_not_allowed
  • model_not_available
  • all_fallbacks_failed
  • no_fallback_available
  • fallback_blocked_for_cache_consistency

Balance and payment

  • memory_balance_required
  • webSearch_balance_required
  • both_balance_required

Rate limiting

  • rate_limit_exceeded
  • daily_rpd_limit_exceeded
  • daily_usd_limit_exceeded

Streaming Errors

When using Server-Sent Events ("stream": true), errors can happen:
  • Before streaming begins (you get a normal JSON error response with an HTTP status code)
  • Mid-stream (you may receive an error frame/chunk, or the connection may terminate)
Example (mid-stream error frame):
data: {"id":"chatcmpl_...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"error"}],"error":{"status":503,"message":"Service temporarily unavailable. Please try again later.","code":"service_unavailable"}}
data: [DONE]
If an error happens mid-stream, treat it as a failed request:
  • Surface/log the error message
  • Log the X-Request-ID header if available
  • Retry only when the status/category indicates it is safe to retry (for example 408/429/500/503)

Retry Guidance

General retry recommendations:
  • Retry: 408, 429, 500, 503 (use exponential backoff and respect Retry-After)
  • Do not blindly retry: 400, 401, 402, 403, 404, 409, 413
Suggested backoff (example):
Attempt 1: 1s
Attempt 2: 2s
Attempt 3: 4s
Add jitter to avoid synchronized retries. If you need current guidance on global rate limits, see Rate Limits.

Daily Per-Key Limit Notes

NanoGPT can enforce optional per-key daily limits (Requests/Day and USD/Day). When a daily limit is exceeded, the API returns 429 and typically includes a Retry-After header indicating the number of seconds until the next reset at 00:00 UTC.

Balance Errors (402)

Some endpoints return 402 Payment Required when payment is needed before the request can run. There are two common cases.

Authenticated Balance Error

{
  "error": "Insufficient balance",
  "requiredBalance": 0.0035,
  "status": 402
}
This is the ordinary insufficient-balance response for authenticated requests.

Accountless x402 Payment Challenge

Supported endpoints can also be called without Authorization or x-api-key. If the request can be quoted, NanoGPT returns a 402 response with a stable top-level payment object plus legacy OpenAI-compatible error fields. Detect accountless x402 by checking for the top-level payment object, not a single error.code value.
{
  "error": {
    "type": "insufficient_quota",
    "code": "insufficient_quota",
    "message": "Payment required to complete this request."
  },
  "payment": {
    "version": 1,
    "paymentId": "pay_...",
    "requestHash": "sha256:...",
    "expiresAt": "2026-06-09T12:00:00.000Z",
    "amountUsd": "0.0714",
    "statusUrl": "https://nano-gpt.com/api/x402/status/pay_...",
    "completeUrl": "https://nano-gpt.com/api/x402/complete/pay_...",
    "accepted": [
      {
        "scheme": "nano",
        "protocolScheme": "nano",
        "network": "nano-mainnet",
        "amount": "...",
        "amountFormatted": "0.17067988 XNO",
        "amountUsd": "0.0714",
        "payTo": "nano_...",
        "paymentId": "pay_...",
        "statusUrl": "https://nano-gpt.com/api/x402/status/pay_...",
        "completeUrl": "https://nano-gpt.com/api/x402/complete/pay_..."
      },
      {
        "scheme": "x402-solana-usdc",
        "protocolScheme": "exact",
        "network": "solana",
        "amount": "1500",
        "amountFormatted": "0.0015 USDC",
        "amountUsd": "0.0015",
        "payTo": "<solana treasury address from quote>",
        "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "feePayer": "<solana facilitator fee payer from quote>",
        "paymentId": "pay_...",
        "expiresAt": "2026-06-09T12:00:00.000Z"
      }
    ]
  },
  "x402Version": 1,
  "accepts": []
}
The legacy accepts array may still appear for backwards-compatible and lower-level protocol clients, but new clients should use payment.accepted[]. Exact rails such as nano-exact, x402-exact, and x402-solana-usdc replay the original request with X-PAYMENT; polling-style rails such as nano and base-usdc use statusUrl and completeUrl. See Accountless x402 API Payments for the complete flow and supported endpoint matrix. Feature-specific variants may include a structured error code such as memory_balance_required or webSearch_balance_required.

Content Policy and Empty Responses

  • If a request is blocked by safety checks (content_policy_violation), the API will return a 400 error and is intended to avoid charging for the blocked generation request. If Inline Moderation blocked the request, the separate moderation preflight is still charged.
  • If the API returns empty_response, the request is intended to avoid charging (common causes: stop sequences, very low max_tokens, or filtering).

BYOK Notes

When using BYOK (Bring Your Own Key), some error messages may reference “your API key” because the upstream credentials belong to you.