{"record":{"id":"bec906df437f7630","repo":"openclaw/openclaw","slug":"codex-settled-turn-projection-found-unsupported-us","errorCode":null,"errorMessage":"Codex settled-turn projection found unsupported user content","messagePattern":"Codex settled-turn projection found unsupported user content","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extensions/codex/src/app-server/settled-turn-projection.ts","lineNumber":116,"sourceCode":"        type: \"message\",\n        role: \"user\",\n        content: [\n          { type: \"input_text\", text: requireBoundedText(upstreamUserText, \"upstream user text\") },\n        ],\n      },\n    ];\n  }\n  if (typeof record.content === \"string\") {\n    return [\n      {\n        type: \"message\",\n        role: \"user\",\n        content: [{ type: \"input_text\", text: requireBoundedText(record.content, \"user message\") }],\n      },\n    ];\n  }\n  if (!Array.isArray(record.content)) {\n    throw new Error(\"Codex settled-turn projection found unsupported user content\");\n  }\n  const content: JsonValue[] = [];\n  for (const value of record.content) {\n    if (!isRecord(value)) {\n      throw new Error(\"Codex settled-turn projection found malformed user content\");\n    }\n    if (value.type === \"text\") {\n      const text = readBoundedText(value.text, \"user text\");\n      if (text) {\n        content.push({ type: \"input_text\", text });\n      }\n      continue;\n    }\n    throw new Error(\n      `Codex settled-turn projection does not support user content ${String(value.type)}`,\n    );\n  }\n  if (content.length === 0) {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/openclaw/openclaw/blob/01804a75319da4b69c9ab98ceaa30477e22b8c0b/extensions/codex/src/app-server/settled-turn-projection.ts#L98-L134","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst msg = { role: \"user\", content: 404 }; // throws\n\n// after\nconst msg = { role: \"user\", content: \"Not found\" };","handlingStrategy":"type-guard","validationCode":"function isSupportedUserContent(content: unknown): boolean {\n  return typeof content === \"string\" || Array.isArray(content);\n}\n\n// before projection, normalize or drop unsupported user messages\nif (!isSupportedUserContent(message.content)) message.content = String(message.content ?? \"\");","typeGuard":"function isStringOrArray(value: unknown): value is string | unknown[] {\n  return typeof value === \"string\" || Array.isArray(value);\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["codex","settled-turn","projection","user-message","content","validation"],"backgroundTag":null,"analyzedSha":"01804a75319da4b69c9ab98ceaa30477e22b8c0b","analyzedAt":"2026-08-12T04:37:58.197Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}