HeyPuter/puter · error · HttpError

bad_response

bad_response

Error message

an empty response was generated

What it means

Thrown by the Responses-API output handler (handle_completion_output_responses_api) when completion.output_text is empty after trimming AND there are no function_call tool calls AND no compaction artifact in the output. The comment notes GPT normally won't produce an empty response on demand, so this is treated as an upstream error condition rather than valid output.

Source

Thrown at src/backend/drivers/ai-chat/utils/OpenAIUtil.js:557

        .map((item) => ({
            id: item.call_id,
            type: 'function',
            function: {
                name: item.name,
                arguments: item.arguments,
            },
            ...(item.id ? { canonical_id: item.id } : {}),
        }));

    // Inline-compaction artifact, if the upstream compacted this turn.
    const compactionItem = output.find((item) => item?.type === 'compaction');

    const is_empty = completion.output_text.trim() === '';
    if (is_empty && responseToolCalls.length < 1 && !compactionItem) {
        // GPT refuses to generate an empty response if you ask it to,
        // so this will probably only happen on an error condition.
        // A compaction-only output is legitimate, so don't reject it.
        throw new HttpError(400, 'an empty response was generated', {
            legacyCode: 'bad_response',
        });
    }

    // We need to moderate the completion too
    const mod_text = completion.output_text;
    if (moderate && mod_text !== null) {
        const moderation_result = await moderate(mod_text);
        if (moderation_result.flagged) {
            throw new HttpError(400, 'message is not allowed', {
                legacyCode: 'bad_request',
            });
        }
    }

    const ret = {
        finish_reason: 'stop',
        index: 0,

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Retry the request once — empty responses are usually transient upstream errors.
  2. Simplify or fix the message history being sent (remove malformed/empty user turns).
  3. If reproducible, capture the raw completion to see whether the model returned reasoning-only or errored, then adjust the request.
  4. Catch HTTP 400 'an empty response was generated' and fall back to a different model.

Example fix

// before
const r = await puter.ai.chat(messages, { model: 'gpt-5-response' });
// after — retry once on empty
let r;
try { r = await puter.ai.chat(messages, { model: 'gpt-5-response' }); }
catch (e) {
  if (e.code === 'bad_response' && /empty response/.test(e.message)) {
    r = await puter.ai.chat(messages, { model: 'gpt-5-response' }); // one retry
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate message history before sending — drop empty/whitespace user turns.
const clean = messages.filter(m => !(m.role === 'user' && String(m.content ?? '').trim() === ''));
if (clean.length === 0) throw new Error('no non-empty messages');

Try / catch

let resp;
try {
  resp = await puter.ai.chat(messages, { stream: false });
} catch (e) {
  if (e?.code === 'bad_response' && /empty response/i.test(e?.message)) {
    resp = await puter.ai.chat(messages, { stream: false }); // single retry
  } else throw e;
}

Prevention

When it happens

Trigger: A Responses-API chat call returns a completion whose output_text is whitespace-only/empty, with no tool_calls and no inline compaction item — e.g. upstream model error, truncated response, or a degenerate request the model couldn't answer.

Common situations: Upstream provider hiccup, model overloaded/refused mid-generation, malformed message history that yields nothing, or an edge case where the model emits only reasoning and no visible output.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/0f238e55cc05a445. Report an issue: GitHub.