jackwener/OpenCLI · error · CommandExecutionError
Malformed ChatGPT conversation payload for Deep Research ext
Error message
Malformed ChatGPT conversation payload for Deep Research extraction.
What it means
extractDeepResearchFromConversationPayload validates the conversation payload before extracting Deep Research progress. A payload that is not a non-array object (null, a string, a number, or an Array) cannot contain conversation fields or a message mapping, so the library throws immediately rather than returning a partial result.
Source
Thrown at clis/chatgpt/utils.js:1531
const report = normalizeDeepResearchText(parts.filter((part) => typeof part === 'string').join('\n\n'));
if (looksLikeDeepResearchReport(report)) {
return {
status: 'completed',
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,View on GitHub (pinned to 49907e53dc)
Solutions
- Ensure the fetch response is awaited with .json() before passing it in, and check res.ok first.
- Parse strings with JSON.parse and validate the result is a non-array object before extraction.
- Wrap the call in try-catch and surface a user-friendly 'unexpected ChatGPT response' message.
- Verify the endpoint actually returns the conversation payload shape ({conversation_id, mapping, ...}).
Example fix
// before
const result = extractDeepResearchFromConversationPayload(await res.text());
// after
const payload = await res.json();
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) throw new Error('Unexpected ChatGPT response');
const result = extractDeepResearchFromConversationPayload(payload); Defensive patterns
Strategy: type-guard
Validate before calling
function assertConversationPayload(p) {
if (!p || typeof p !== 'object' || Array.isArray(p)) throw new Error('payload must be a non-array object');
if (!p.mapping || typeof p.mapping !== 'object') throw new Error('payload missing mapping');
} Type guard
const isConversationPayload = (p) => !!p && typeof p === 'object' && !Array.isArray(p) && typeof p.mapping === 'object' && p.mapping !== null && !Array.isArray(p.mapping);
Try / catch
let payload;
try {
payload = await res.json();
} catch (e) {
throw new Error(`ChatGPT returned non-JSON body: ${e.message}`);
}
try {
return extractDeepResearchFromConversationPayload(payload, { expectedConversationId });
} catch (err) {
if (String(err.message).includes('Malformed ChatGPT conversation payload')) {
return { progress: null, reason: 'unexpected payload shape' };
}
throw err;
} Prevention
- Always call res.json() (never pass raw text) before extraction
- Check res.ok and content-type before parsing
- Validate payload shape with a type guard prior to extraction
- Ensure you pass one payload object, not an array of chunks
When it happens
Trigger: Calling extractDeepResearchFromConversationPayload with a null/undefined payload, a JSON string not yet parsed, an array of payloads, or an HTTP response body that failed JSON parsing.
Common situations: API returning an error page/HTML string instead of JSON; response.json() misused or response.text() passed directly; fetch following a redirect to a non-JSON endpoint; passing an array of conversation chunks instead of a single payload object.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
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
- ChatGPT conversation payload id mismatch: expected ${expecte
- INVALID_ARGUMENT
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9138f01c2e043ca0.
Report an issue: GitHub.