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
- Rephrase or constrain the conversation so the model is unlikely to emit flagged content (tighten the system prompt).
- Inspect the moderator configuration/ thresholds if benign completions are being flagged.
- If streaming is acceptable, use stream:true — note moderation still applies but surfaces differently; the 400 here is the non-stream path.
- 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
- Keep the system prompt tightly scoped to reduce the chance of flagged completions.
- Catch bad_request / 'not allowed' specifically and show a policy notice rather than crashing.
- If benign output is repeatedly flagged, review the moderator configuration.
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.