pbakaus/impeccable · error

generate-image: API error {}: {}

Error message

generate-image: API error {}: {}

What it means

The OpenAI image API returned an HTTP status outside 200..299. generate-image prints the status plus the first 300 characters of the response body and exits 1. This surfaces API-side rejections such as bad requests, authentication failures, or rate limits.

Source

Thrown at crates/context/src/generate_image.rs:363

            .post("https://api.openai.com/v1/images/generations")
            .set("Authorization", &format!("Bearer {}", key))
            .set("content-type", "application/json")
            .send_string(&serde_json::to_string(&Value::Object(m)).unwrap())
    };
    let (status, text) = match response {
        Ok(r) => {
            let st = r.status();
            (st, r.into_string().unwrap_or_default())
        }
        Err(ureq::Error::Status(code, r)) => (code, r.into_string().unwrap_or_default()),
        Err(e) => {
            io.err(&format!("TypeError: fetch failed: {}\n", e));
            return 1;
        }
    };
    if !(200..300).contains(&status) {
        let snippet: String = text.chars().take(300).collect();
        io.err(&format!("generate-image: API error {}: {}\n", status, snippet));
        return 1;
    }
    let json: Value = serde_json::from_str(&text).unwrap_or(Value::Null);
    let b64 = json.get("data").and_then(|d| d.get(0)).and_then(|d| d.get("b64_json")).and_then(|b| b.as_str()).filter(|s| !s.is_empty());
    let Some(b64) = b64 else {
        io.err("generate-image: no image in response\n");
        return 1;
    };
    let bytes = base64_decode(b64);
    let _ = std::fs::write(abs(&out), bytes);
    // best-effort embed + sidecar
    // JS-PARITY: generate-image.mjs#676 reports whether the embed actually
    // succeeded. The install-path-with-spaces half of #676 is a JS-only
    // subprocess concern (fileURLToPath vs URL.pathname); the engine embeds
    // in-process, so only the success tracking and message carry over here.
    let embedded;
    {
        let mut sub_io = Io::captured("", io.cwd.clone(), io.env.clone()).0;

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Read the status and body snippet in the message: 401 → fix the API key; 429 → wait/retry with backoff; 400 → correct size/quality/ref parameters.
  2. Verify OPENAI_API_KEY is valid and has billing/quota enabled for the org.
  3. Reduce or validate inputs (smaller size, supported quality value, fewer/smaller reference images) and retry.
  4. Check the OpenAI status page for ongoing incidents if you see 5xx.
  5. Implement retry with exponential backoff for 429/5xx responses in any wrapper scripts.

Example fix

// before
impeccable generate-image --size 9999x9999 --prompt "..." --out o.png
// generate-image: API error 400: ...
// after
impeccable generate-image --size 1536x1024 --prompt "..." --out o.png
Defensive patterns

Strategy: retry

Validate before calling

// preflight the key and known-good parameters
if (!process.env.OPENAI_API_KEY?.startsWith("sk-")) throw new Error("invalid OPENAI_API_KEY");
const ALLOWED_SIZES = ["1024x1024", "1536x1024", "1024x1536"];
if (!ALLOWED_SIZES.includes(size)) throw new Error(`unsupported size: ${size}`);

Try / catch

const r = spawnSync("impeccable", ["generate-image", ...], { encoding: "utf8" });
if (r.status !== 0) {
  const m = r.stderr.match(/API error (\d+)/);
  if (m && (m[1] === "429" || m[1].startsWith("5"))) {
    await backoffAndRetry();
  } else if (m && m[1] === "401") {
    throw new Error("OPENAI_API_KEY rejected — rotate/fix the key");
  } else throw new Error(r.stderr);
}

Prevention

When it happens

Trigger: POST to the images endpoint returns 4xx/5xx: 401 for an invalid/revoked OPENAI_API_KEY, 400 for an invalid size/quality/parameter combination, 429 for rate limiting or quota exhaustion, 5xx for OpenAI outages.

Common situations: Expired or rotated API keys; requesting a size not supported by the model; free-tier quota exhausted; org billing issue; transient OpenAI incidents; sending reference images that are too large.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/0f101ecfe31fa826. Report an issue: GitHub.