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

  1. Inspect record.content type on the offending user message.
  2. Ensure the producer (channel/normalization layer) sets content to a string or an array of typed parts.
  3. 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

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


AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12). Data as JSON: /api/errors/bec906df437f7630. Report an issue: GitHub.