jackwener/OpenCLI · error · CommandExecutionError
ChatGPT conversation payload id mismatch: expected ${expecte
Error message
ChatGPT conversation payload id mismatch: expected ${expectedConversationId}, got ${payloadConversationId}. What it means
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.
Source
Thrown at clis/chatgpt/utils.js:1535
report,
html: '',
method: source,
sources: extractDeepResearchSourcesFromReportMessage(reportMessage),
widgetStatus: String(widgetStateObject.status || ''),
reportMessageId: String(reportMessage?.id || ''),
reportLength: report.length,
};
}
return buildDeepResearchProgressResult(widgetStateObject, pickFirstObject(responseMetadata), source);
}
function extractDeepResearchFromConversationPayload(payload, { expectedConversationId = '' } = {}) {
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new CommandExecutionError('Malformed ChatGPT conversation payload for Deep Research extraction.');
}
const payloadConversationId = String(payload.conversation_id || payload.conversationId || payload.id || '').trim();
if (expectedConversationId && payloadConversationId && payloadConversationId !== expectedConversationId) {
throw new CommandExecutionError(
`ChatGPT conversation payload id mismatch: expected ${expectedConversationId}, got ${payloadConversationId}.`,
);
}
const mapping = payload?.mapping && typeof payload.mapping === 'object' ? payload.mapping : {};
if (!payload.mapping || typeof payload.mapping !== 'object' || Array.isArray(payload.mapping)) {
throw new CommandExecutionError('Malformed ChatGPT conversation payload for Deep Research extraction: missing mapping.');
}
const candidates = [];
for (const [messageId, node] of Object.entries(mapping)) {
const message = node?.message || {};
const metadata = message?.metadata || {};
const sdk = metadata?.chatgpt_sdk || {};
const responseMetadata = pickFirstObject(
sdk?.response_metadata,
sdk?.responseMetadata,
metadata?.response_metadata,
metadata?.responseMetadata,
);View on GitHub (pinned to 49907e53dc)
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.
Example fix
// before
const data = cache.get(anyConversationId) || await fetchConversation(id);
return extractDeepResearchFromConversationPayload(data, { expectedConversationId: id });
// after
const data = await fetchConversation(id); // cache key: `conv:${id}`
return extractDeepResearchFromConversationPayload(data, { expectedConversationId: id }); Defensive patterns
Strategy: validation
Validate before calling
const payloadId = String(payload?.conversation_id || payload?.conversationId || payload?.id || '').trim();
if (expectedId && payloadId && payloadId !== expectedId) {
throw new Error(`stale/mismatched payload: ${payloadId} != ${expectedId}`);
} Type guard
const matchesConversation = (p, id) => !!p && typeof p === 'object' && String(p.conversation_id || p.conversationId || p.id || '').trim() === id;
Try / catch
try {
return extractDeepResearchFromConversationPayload(payload, { expectedConversationId: id });
} catch (err) {
if (String(err.message).includes('id mismatch')) {
const fresh = await fetchConversation(id); // bypass cache and retry once
return extractDeepResearchFromConversationPayload(fresh, { expectedConversationId: id });
}
throw err;
} Prevention
- 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
When it happens
Trigger: extractDeepResearchFromConversationPayload(payload, {expectedConversationId: 'X'}) receives a payload whose trimmed conversation_id/conversationId/id is a different non-empty string 'Y'.
Common situations: 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.
Related errors
- Malformed ChatGPT Deep Research ${label}: expected object so
- Malformed ChatGPT Deep Research ${label}: missing source URL
- Malformed ChatGPT Deep Research ${label}: invalid source URL
- Malformed ChatGPT conversation payload for Deep Research ext
- INVALID_ARGUMENT
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/61051735cc02637f.
Report an issue: GitHub.