openclaw/openclaw · error
Codex settled-turn projection found unsupported user content
Error message
Codex settled-turn projection found unsupported user content
What it means
Thrown by projectUserMessage when message.content is neither a string nor an array. The projection supports only string content (treated as a single input_text) or an array of typed content parts; any other type (number, boolean, plain object, null) is unsupported.
Source
Thrown at extensions/codex/src/app-server/settled-turn-projection.ts:116
type: "message",
role: "user",
content: [
{ type: "input_text", text: requireBoundedText(upstreamUserText, "upstream user text") },
],
},
];
}
if (typeof record.content === "string") {
return [
{
type: "message",
role: "user",
content: [{ type: "input_text", text: requireBoundedText(record.content, "user message") }],
},
];
}
if (!Array.isArray(record.content)) {
throw new Error("Codex settled-turn projection found unsupported user content");
}
const content: JsonValue[] = [];
for (const value of record.content) {
if (!isRecord(value)) {
throw new Error("Codex settled-turn projection found malformed user content");
}
if (value.type === "text") {
const text = readBoundedText(value.text, "user text");
if (text) {
content.push({ type: "input_text", text });
}
continue;
}
throw new Error(
`Codex settled-turn projection does not support user content ${String(value.type)}`,
);
}
if (content.length === 0) {View on GitHub (pinned to 01804a7531)
Solutions
- Inspect record.content type on the offending user message.
- Ensure the producer (channel/normalization layer) sets content to a string or an array of typed parts.
- If content is genuinely absent, drop the message before projection rather than passing it through.
Example fix
// before
const msg = { role: "user", content: 404 }; // throws
// after
const msg = { role: "user", content: "Not found" }; Defensive patterns
Strategy: type-guard
Validate before calling
function isSupportedUserContent(content: unknown): boolean {
return typeof content === "string" || Array.isArray(content);
}
// before projection, normalize or drop unsupported user messages
if (!isSupportedUserContent(message.content)) message.content = String(message.content ?? ""); Type guard
function isStringOrArray(value: unknown): value is string | unknown[] {
return typeof value === "string" || Array.isArray(value);
} Prevention
- Always set user message content to a string or an array of typed parts.
- Drop user messages with absent content before projection rather than passing them through.
- Validate message shapes at the channel/normalization boundary.
When it happens
Trigger: A user AgentMessage whose content field is a number, boolean, plain object, or null; a channel adapter that set content to an integer code or an object payload; a normalized message that lost its string/array content during migration.
Common situations: Channel adapter forwarding a structured payload into content instead of a text part; legacy message shape with numeric status code in content; test fixture with content set to null.
Related errors
- Codex settled-turn projection found malformed user content
- Codex settled-turn projection found an empty user message
- Codex settled-turn projection found unsupported assistant co
- Codex settled-turn projection found malformed assistant cont
- Codex settled-turn projection found oversized ${label}
AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12).
Data as JSON: /api/errors/bec906df437f7630.
Report an issue: GitHub.