{"record":{"id":"61051735cc02637f","repo":"jackwener/OpenCLI","slug":"chatgpt-conversation-payload-id-mismatch-expected","errorCode":null,"errorMessage":"ChatGPT conversation payload id mismatch: expected ${expectedConversationId}, got ${payloadConversationId}.","messagePattern":"ChatGPT conversation payload id mismatch: expected (.+?), got (.+?)\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chatgpt/utils.js","lineNumber":1535,"sourceCode":"            report,\n            html: '',\n            method: source,\n            sources: extractDeepResearchSourcesFromReportMessage(reportMessage),\n            widgetStatus: String(widgetStateObject.status || ''),\n            reportMessageId: String(reportMessage?.id || ''),\n            reportLength: report.length,\n        };\n    }\n    return buildDeepResearchProgressResult(widgetStateObject, pickFirstObject(responseMetadata), source);\n}\n\nfunction extractDeepResearchFromConversationPayload(payload, { expectedConversationId = '' } = {}) {\n    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n        throw new CommandExecutionError('Malformed ChatGPT conversation payload for Deep Research extraction.');\n    }\n    const payloadConversationId = String(payload.conversation_id || payload.conversationId || payload.id || '').trim();\n    if (expectedConversationId && payloadConversationId && payloadConversationId !== expectedConversationId) {\n        throw new CommandExecutionError(\n            `ChatGPT conversation payload id mismatch: expected ${expectedConversationId}, got ${payloadConversationId}.`,\n        );\n    }\n    const mapping = payload?.mapping && typeof payload.mapping === 'object' ? payload.mapping : {};\n    if (!payload.mapping || typeof payload.mapping !== 'object' || Array.isArray(payload.mapping)) {\n        throw new CommandExecutionError('Malformed ChatGPT conversation payload for Deep Research extraction: missing mapping.');\n    }\n    const candidates = [];\n    for (const [messageId, node] of Object.entries(mapping)) {\n        const message = node?.message || {};\n        const metadata = message?.metadata || {};\n        const sdk = metadata?.chatgpt_sdk || {};\n        const responseMetadata = pickFirstObject(\n            sdk?.response_metadata,\n            sdk?.responseMetadata,\n            metadata?.response_metadata,\n            metadata?.responseMetadata,\n        );","sourceCodeStart":1517,"sourceCodeEnd":1553,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chatgpt/utils.js#L1517-L1553","documentation":"When the caller passes expectedConversationId, the payload's own id (from conversation_id, conversationId, or id) must match it exactly. A mismatch means the response body belongs to a different conversation than the one requested, which would leak or attach Deep Research progress to the wrong thread, so the library throws.","triggerScenarios":"extractDeepResearchFromConversationPayload(payload, {expectedConversationId: 'X'}) receives a payload whose trimmed conversation_id/conversationId/id is a different non-empty string 'Y'.","commonSituations":"Caching layer returning a previous conversation's payload for a new id; backend reusing/redirecting to another conversation; client comparing against the wrong id field (e.g. message id vs conversation id); race where the conversation id changed after regeneration.","solutions":["Verify the request URL/conversation id matches the one used to fetch the payload (fix off-by-one id selection in the caller).","Bypass cache or include the conversation id in the cache key so stale payloads are never returned.","Log both ids on mismatch and re-fetch the conversation before extraction.","If the mismatch is expected (e.g. server-assigned ids), only pass expectedConversationId when strict verification is required."],"exampleFix":"// before\nconst data = cache.get(anyConversationId) || await fetchConversation(id);\nreturn extractDeepResearchFromConversationPayload(data, { expectedConversationId: id });\n// after\nconst data = await fetchConversation(id); // cache key: `conv:${id}`\nreturn extractDeepResearchFromConversationPayload(data, { expectedConversationId: id });","handlingStrategy":"validation","validationCode":"const payloadId = String(payload?.conversation_id || payload?.conversationId || payload?.id || '').trim();\nif (expectedId && payloadId && payloadId !== expectedId) {\n  throw new Error(`stale/mismatched payload: ${payloadId} != ${expectedId}`);\n}","typeGuard":"const matchesConversation = (p, id) =>\n  !!p && typeof p === 'object' && String(p.conversation_id || p.conversationId || p.id || '').trim() === id;","tryCatchPattern":"try {\n  return extractDeepResearchFromConversationPayload(payload, { expectedConversationId: id });\n} catch (err) {\n  if (String(err.message).includes('id mismatch')) {\n    const fresh = await fetchConversation(id); // bypass cache and retry once\n    return extractDeepResearchFromConversationPayload(fresh, { expectedConversationId: id });\n  }\n  throw err;\n}","preventionTips":["Key caches by conversation id so stale payloads can't be served","Confirm the id you compare against is the conversation id, not a message id","Re-fetch the conversation when a mismatch is detected instead of reusing cached data","Log both expected and actual ids whenever this error fires"],"tags":["validation","deep-research","id-mismatch"],"backgroundTag":"id-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}