HeyPuter/puter · error · HttpError

bad_request

bad_request

Error message

message is not allowed

What it means

Thrown by the non-streaming chat-completion path in handle_completion_output after the model returns. Puter runs the model's own assistant content through its moderation function; if moderation flags it (moderation_result.flagged === true), the response is rejected with HTTP 400. It is content-policy enforcement on the completion, not on the user's prompt.

Source

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

            completion,
            usage_calculator,
        });

        return {
            stream: true,
            init_chat_stream,
            finally_fn,
        };
    }

    if (finally_fn) await finally_fn();

    // We need to moderate the completion too
    const mod_text = completion.choices[0].message.content;
    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 = completion.choices[0];
    const completion_usage = deviations.coerce_completion_usage(completion);
    ret.usage = usage_calculator
        ? usage_calculator({
              ...completion,
              usage: completion_usage,
          })
        : {
              input_tokens: completion_usage.prompt_tokens,
              output_tokens: completion_usage.completion_tokens,
          };
    return ret;
};

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Rephrase or constrain the conversation so the model is unlikely to emit flagged content (tighten the system prompt).
  2. Inspect the moderator configuration/ thresholds if benign completions are being flagged.
  3. If streaming is acceptable, use stream:true — note moderation still applies but surfaces differently; the 400 here is the non-stream path.
  4. Catch the 400 'message is not allowed' client-side and show the user a content-policy message instead of crashing.

Example fix

// before
const resp = await puter.ai.chat('write something edgy');
// after — guard the policy error
try {
  const resp = await puter.ai.chat(prompt, { stream: false });
} catch (e) {
  if (e.code === 'bad_request' && /not allowed/.test(e.message)) {
    showUser('Response blocked by content policy.');
    return;
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-screen the user prompt only; you cannot pre-predict model-output moderation.
// Validate prompt is a non-empty string before the call:
if (typeof prompt !== 'string' || prompt.trim() === '') {
  throw new Error('prompt required');
}

Try / catch

try {
  const resp = await puter.ai.chat(prompt, { stream: false });
} catch (e) {
  if (e?.code === 'bad_request' && /not allowed/i.test(e?.message)) {
    showContentPolicyNotice();
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A non-streaming AI chat call (puter.ai.chat with stream:false, or any provider routed through handle_completion_output) whose model output contains text the moderation layer considers disallowed.

Common situations: The model produces output touching violence, sexual content, hate, self-harm, or other policy categories the configured moderator screens for; or a mis-configured/over-aggressive moderator flags benign output.

Related errors


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