{"record":{"id":"83b8441df792bc3b","repo":"can1357/oh-my-pi","slug":"openai-responses-compaction-input-contains-a-non-o","errorCode":null,"errorMessage":"OpenAI Responses compaction input contains a non-object item","messagePattern":"OpenAI Responses compaction input contains a non-object item","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/compaction/compaction.ts","lineNumber":1459,"sourceCode":"\nfunction buildOpenAiResponsesCompactionInput(\n\tmessages: Message[],\n\tmodel: Model<\"openai-responses\" | \"azure-openai-responses\" | \"openai-codex-responses\">,\n\tpreviousReplacementHistory: Array<Record<string, unknown>> | undefined,\n): Array<Record<string, unknown>> {\n\tconst input = buildResponsesInput({\n\t\tmodel,\n\t\tcontext: { messages },\n\t\tstrictResponsesPairing: model.compat.strictResponsesPairing,\n\t\tsupportsImageDetailOriginal: openAiCompatSupportsImageDetailOriginal(model),\n\t\tnativeHistory: { replay: true, filterReasoning: false },\n\t\tincludeThinkingSignatures: true,\n\t\trepairOrphanOutputs: true,\n\t});\n\tconst nativeInput: Array<Record<string, unknown>> = [];\n\tfor (const item of input) {\n\t\tif (!isRecord(item)) {\n\t\t\tthrow new Error(\"OpenAI Responses compaction input contains a non-object item\");\n\t\t}\n\t\tnativeInput.push(item);\n\t}\n\treturn stripOpenAIResponsesOutputOnlyStatusesForReplay(\n\t\tpreviousReplacementHistory ? [...previousReplacementHistory, ...nativeInput] : nativeInput,\n\t);\n}\n\n/**\n * Resolve the Responses `reasoning` param for a V2 compaction request the same\n * way a normal turn does — through {@link resolveOpenAICompatPolicy}, so it\n * honors per-model effort support, `omitReasoningEffort`, disable modes, and the\n * wire-effort mapping. Returns `undefined` for non-reasoning models or when the\n * user selected `Off` (matching the normal-turn omission, not a fabricated shape).\n */\nfunction buildCompactionV2Reasoning(\n\tmodel: Model<\"openai-responses\" | \"azure-openai-responses\" | \"openai-codex-responses\">,\n\tthinkingLevel: ThinkingLevel | undefined,","sourceCodeStart":1441,"sourceCodeEnd":1477,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/agent/src/compaction/compaction.ts#L1441-L1477","documentation":"When preparing OpenAI Responses input for compaction, every input item must be a plain object (Record<string, unknown>); the code validates each item after transforming the session history and throws if any element is not an object. This catches corrupted or wrongly-shaped history before it is sent to the API.","triggerScenarios":"The serialized/transformed session input array contains a non-object element — e.g. a raw string, number, null, or undefined item introduced by a custom session format, a buggy converter/filter upstream, or hand-edited/corrupted session JSONL.","commonSituations":"Custom message transforms or plugins pushing plain strings into the input array; older session files with a different message schema merged into a new-format session; scripts that patch session history and insert raw text items.","solutions":["Inspect the session history/messages feeding the compaction for non-object entries (null, string, number) and fix or remove them","Validate/normalize items before compaction — ensure each message passes the provider's input transform and remains an object","If a converter or plugin mutates input, fix it to emit record-shaped items matching the OpenAI Responses input schema","Re-export or rebuild the session from its source if the stored history is corrupted"],"exampleFix":"// before\ninput.push(\"summarize this\") // raw string item\n// after\ninput.push({ role: \"user\", content: [{ type: \"input_text\", text: \"summarize this\" }] })","handlingStrategy":"validation","validationCode":"const bad = input.findIndex((item) => item === null || typeof item !== \"object\");\nif (bad !== -1) {\n  throw new Error(`input[${bad}] is not an object: ${JSON.stringify(input[bad])}`);\n}","typeGuard":"function isRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  await compact(session);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"non-object item\")) {\n    sanitizeHistory(session); // drop/normalize malformed entries\n    return compact(session);\n  }\n  throw err;\n}","preventionTips":["Normalize every history item through the provider input transform before compaction","Reject/repair string or null message items at session load time","Add a record-shape type guard at the boundary where custom plugins inject messages"],"tags":["compaction","validation","openai","input-shape","session-history"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}