Models
Failure Tempest 1All modelsStatus
Research
OverviewAPI fusionEvaluation
Developers
DocumentationConsoleChangelog
Company
PricingEnterpriseAboutSecurityContact
Account
Sign inCreate account
Docs/Errors
Documentation

When it says no.

Errors use the OpenAI shape, so existing SDK error handling works unchanged.

Error shape

{ "error": { "message": "Human-readable explanation.", "type": "insufficient_quota" } }

Status codes

StatusTypeMeaningRetry?
400invalid_request_errorMalformed body, missing messages, bad fieldNo — fix the request
401invalid_api_keyMissing, wrong or revoked keyNo
402insufficient_quotaThe key's monthly spend cap is reachedNot until the 1st (UTC), or raise the cap
404invalid_request_errorUnknown model id or routeNo
503service_unavailableNot live yet, or the router is restartingYes, with backoff

The 400 and 404 type strings follow the OpenAI convention; branch on the HTTP status, which is the stable contract.

Handling errors in Python

import os
import time
import openai
from openai import OpenAI

client = OpenAI(base_url="https://api.failure.fail/v1", api_key=os.environ["FAILURE_API_KEY"], max_retries=0)

def ask(messages, model="failure-tempest-1", attempts=5):
    delay = 1.0
    for i in range(attempts):
        try:
            return client.chat.completions.create(model=model, messages=messages)
        except openai.APIStatusError as e:
            if e.status_code == 402:
                # Spend cap reached: stop, tell a human, do not retry.
                raise RuntimeError("Monthly spend cap reached for this key.") from e
            if e.status_code == 503 and i < attempts - 1:
                time.sleep(delay)
                delay = min(delay * 2, 30)
                continue
            raise

Handling errors in TypeScript

import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.failure.fail/v1", apiKey: process.env.FAILURE_API_KEY, maxRetries: 0 });
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

export async function ask(messages: OpenAI.ChatCompletionMessageParam[], model = "failure-tempest-1") {
  let delay = 1000;
  for (let i = 0; i < 5; i++) {
    try {
      return await client.chat.completions.create({ model, messages });
    } catch (e) {
      if (e instanceof OpenAI.APIError) {
        if (e.status === 402) throw new Error("Monthly spend cap reached for this key.");
        if (e.status === 503 && i < 4) {
          await sleep(delay);
          delay = Math.min(delay * 2, 30000);
          continue;
        }
      }
      throw e;
    }
  }
}

The 503 before launch

Until Failure Tempest 1 is live, chat completions return:

{ "error": { "message": "not live yet", "type": "service_unavailable" } }

Poll GET /v1/status (public, no key) and check live instead of hammering the completions endpoint.

Good habits

  • Retry only 503s, with exponential backoff and a ceiling.
  • Treat 402 as a budget event: alert someone, do not loop.
  • Log error.type and error.message; include them if you write to api@failure.fail.