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

  1. Ensure the fetch response is awaited with .json() before passing it in, and check res.ok first.
  2. Parse strings with JSON.parse and validate the result is a non-array object before extraction.
  3. Wrap the call in try-catch and surface a user-friendly 'unexpected ChatGPT response' message.
  4. 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

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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/9138f01c2e043ca0. Report an issue: GitHub.