different-ai/openwork · error · Error

No output from CUA model.

Error message

No output from CUA model.

What it means

The OpenAI Responses API returned HTTP 200 but result.output was empty, so the loop has nothing to process — no message, no computer_call. The library treats a zero-length output array as a protocol failure rather than silently continuing, since the CUA loop cannot advance without model output.

Source

Thrown at packages/handsfree/src/cua-runner.mjs:41

  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;
    }

    if (!computerCall) return { ok: true, messages, turns: turn + 1 };

    for (const action of computerCall.actions || (computerCall.action ? [computerCall.action] : [])) {
      if (signal?.aborted) return { ok: true, messages, turns: turn + 1, aborted: true };

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Log result.output and result.status — if status is 'incomplete', inspect result.incomplete_details for the reason.
  2. Retry the turn; a single empty output is often transient.
  3. Confirm the model name supports computer-use preview tools; switch to a supported computer-use model.
  4. If OpenAI changed the response shape, update the runner to read the new field (check API changelog).

Example fix

// before
if (!output.length) throw new Error("No output from CUA model.");
// after
if (!output.length && result.status !== "incomplete") throw new Error("No output from CUA model.");
Defensive patterns

Strategy: retry

Type guard

function hasOutput(r: unknown): r is { output: unknown[] } {
  return typeof r === "object" && r !== null && Array.isArray((r as { output?: unknown }).output) && (r as { output: unknown[] }).output.length > 0;
}

Try / catch

try {
  await runCuaLoop(opts);
} catch (e) {
  if (e.message === "No output from CUA model.") {
    // retry the turn once, then surface result.status/incomplete_details
  } else throw e;
}

Prevention

When it happens

Trigger: result.output || [] is empty: the API succeeded but produced no items (e.g. incomplete response, response truncated by the server, an unexpected response shape where output is missing/null, or the model returned only fields the code ignores).

Common situations: OpenAI changes/returns a shape where output items live elsewhere; a model that doesn't support the computer tool returning an empty completion; max_output_tokens set too low elsewhere; intermittent server bug returning 200 with empty body.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/10c95718eb9df17e. Report an issue: GitHub.