jackwener/OpenCLI · error · CommandExecutionError

Malformed ChatGPT conversation payload for Deep Research ext

Error message

Malformed ChatGPT conversation payload for Deep Research extraction: missing mapping.

What it means

Thrown during Deep Research extraction when a ChatGPT conversation payload lacks a valid 'mapping' object. The mapping is the node graph that holds all conversation messages; without it no extraction is possible, so the library fails fast instead of returning empty results.

Source

Thrown at clis/chatgpt/utils.js:1541

            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,
        );
        let sawWidgetState = false;
        for (const widgetState of [
            sdk?.widget_state,
            sdk?.widgetState,
            metadata?.widget_state,
            metadata?.widgetState,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the payload and confirm it is a real backend-api/conversation JSON body containing a 'mapping' key
  2. Re-fetch the conversation and pass response.json() (the raw object), not a wrapped or partial object
  3. Validate payload.mapping is a non-array object before calling the extractor
  4. If upstream changed the schema, update the extraction code to the new field layout

Example fix

// before
await extractDeepResearchFromConversationPayload(JSON.parse(text), { expectedConversationId });
// after
const payload = JSON.parse(text);
if (!payload || typeof payload.mapping !== 'object' || Array.isArray(payload.mapping)) {
  throw new Error('Not a valid conversation payload: mapping missing');
}
await extractDeepResearchFromConversationPayload(payload, { expectedConversationId });
Defensive patterns

Strategy: validation

Validate before calling

function isValidConversationPayload(p) {
  return !!p && typeof p === 'object' && p.mapping && typeof p.mapping === 'object' && !Array.isArray(p.mapping);
}
if (!isValidConversationPayload(payload)) throw new Error('payload.mapping missing — not a conversation payload');

Type guard

function isConversationPayload(p): p is { mapping: Record<string, { message?: unknown }> } {
  return typeof p === 'object' && p !== null && 'mapping' in p
    && typeof (p as any).mapping === 'object' && !Array.isArray((p as any).mapping);
}

Try / catch

try {
  await extractDeepResearchFromConversationPayload(payload, { expectedConversationId });
} catch (e) {
  if (String(e.message).includes('missing mapping')) {
    // re-fetch the conversation or fall back to the network-entry path
  } else throw e;
}

Prevention

When it happens

Trigger: extractDeepResearchFromConversationPayload is called with a payload where payload.mapping is missing, not an object, or is an array — e.g. a truncated or non-conversation JSON body was passed, or an API shape change removed/renamed 'mapping'.

Common situations: Passing a saved conversation export that is actually an error object or HTML-converted JSON; calling with response JSON from a non-conversation endpoint; upstream ChatGPT schema changes; hand-crafted fixtures in tests missing mapping.

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/51d65df175938072. Report an issue: GitHub.