different-ai/openwork · error · Error
CUA API error
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.
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
- Automation request failed
- Billing lookup failed
- Could not load egress diagnostics
- Egress diagnostic could not start
- Failed to load connection details
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/a778368809d515e5.
Report an issue: GitHub.
Appendix: 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)