different-ai/openwork · error · Error
CUA API error ${response.status}: ${errorText.slice(0, 300)}
Error message
CUA API error ${response.status}: ${errorText.slice(0, 300)} What it means
After POSTing the conversation items to the OpenAI computer-use endpoint, runCuaLoop checks response.ok. Any non-2xx (401 invalid key, 402 quota, 429 rate limit, 400 bad model/input, 5xx) becomes this error with the HTTP status and up to 300 chars of the response body, so the actual API error reason is embedded in the message.
Source
Thrown at packages/handsfree/src/cua-runner.mjs:36
onProgress?.({ kind: "start", width: displayInfo.width, height: displayInfo.height });
const items = [{ role: "user", content: String(task ?? "") }];
const messages = [];
for (let turn = 0; turn < maxTurns; turn += 1) {
if (signal?.aborted) return { ok: true, messages, turns: turn, aborted: true };
onProgress?.({ kind: "turn", turn: turn + 1 });
const response = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
body: JSON.stringify({ model, input: items, tools: [{ type: "computer" }] }),
signal,
});
if (!response.ok) {
const errorText = await response.text().catch(() => "");
throw new Error(`CUA API error ${response.status}: ${errorText.slice(0, 300)}`);
}
const result = await response.json();
const output = result.output || [];
if (!output.length) throw new Error("No output from CUA model.");
items.push(...output);
let computerCall = null;
for (const item of output) {
if (item.type === "message") {
const text = item.content?.map((part) => part.text || "").join("") || "";
if (text) {
messages.push(text);
onProgress?.({ kind: "message", text });
}
}
if (item.type === "computer_call") computerCall = item;
}View on GitHub (pinned to 2b7df46e8a)
Solutions
- Read the embedded errorText in the message — it contains OpenAI's JSON error explaining the real cause (e.g. 'Incorrect API key', 'insufficient_quota').
- For 401/402: fix the API key or billing at platform.openai.com; for 429: add backoff/retry with exponential delay.
- For 400: confirm `model` supports the computer-use tool and that pushed items are valid Responses-API output items.
- Wrap the runCuaLoop call in retry logic for 429/5xx statuses before surfacing to the user.
Defensive patterns
Strategy: retry
Try / catch
try {
await runCuaLoop(opts);
} catch (e) {
const m = /CUA API error (\d+)/.exec(e.message);
const status = m ? Number(m[1]) : 0;
if (status === 429 || status >= 500) await backoffRetry(opts);
else throw e; // 401/402/400 are not retryable
} Prevention
- Validate the API key with a cheap models.list call before long-running loops
- Monitor org quota/credits before batch CUA jobs
- Pin a model name known to support the computer-use tool
When it happens
Trigger: Any failed fetch from the loop's model request — invalid/revoked API key (401), out-of-credit org (402), rate limiting (429), unknown `model` name, malformed `items` pushed into the conversation (400), or transient 500/503 from OpenAI.
Common situations: Expired or rotated OpenAI keys; free-tier org with no computer-use access; sending stale tool outputs or oversized screenshots producing a 400; regional outages returning 5xx; corporate proxy stripping the Authorization header.
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
- OpenAI Realtime SDP failed: ${sdpResponse.status} ${detail}
- Automation request failed (${result.response.status}).
- Failed to load connection details (${response.status}).
- Billing lookup failed (${response.status}).
- Failed to load desktop policies (${response.status}).
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/a778368809d515e5.
Report an issue: GitHub.