{"record":{"id":"388ca95421b4c7a2","repo":"jackwener/OpenCLI","slug":"createlist-returned-malformed-json-payload-body","errorCode":null,"errorMessage":"CreateList returned malformed JSON payload. Body: ${String(result.bodyText || '').slice(0, 300)}","messagePattern":"CreateList returned malformed JSON payload\\. Body: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-create.js","lineNumber":52,"sourceCode":"    if (modeRaw !== 'public' && modeRaw !== 'private') {\n        throw new ArgumentError(`Invalid mode: ${JSON.stringify(kwargs.mode)}. Expected \"public\" or \"private\".`);\n    }\n    return { listName: name, listDescription: description, listMode: modeRaw, privateFlag: modeRaw === 'private' };\n}\n\nfunction requireCreateListResult(result, expectedName, expectedMode) {\n    if (!result || typeof result !== 'object') {\n        throw new CommandExecutionError(`Unexpected result from twitter list-create: ${JSON.stringify(result)}`);\n    }\n    if (result.httpStatus === 401 || result.httpStatus === 403) {\n        throw new AuthRequiredError('x.com', `Twitter CreateList returned HTTP ${result.httpStatus}`);\n    }\n    if (!result.ok) {\n        const snippet = String(result.bodyText || '').slice(0, 300);\n        throw new CommandExecutionError(`HTTP ${result.httpStatus} from CreateList: ${snippet}`);\n    }\n    if (!result.bodyJson || typeof result.bodyJson !== 'object') {\n        throw new CommandExecutionError(`CreateList returned malformed JSON payload. Body: ${String(result.bodyText || '').slice(0, 300)}`);\n    }\n    const list = result.bodyJson?.data?.list;\n    if (!list || typeof list !== 'object') {\n        const errors = result.bodyJson?.errors;\n        if (Array.isArray(errors) && errors.length > 0) {\n            throw new CommandExecutionError(`CreateList failed: ${errors[0].message || JSON.stringify(errors[0])}`);\n        }\n        throw new CommandExecutionError(`CreateList returned no list payload. Body: ${String(result.bodyText || '').slice(0, 300)}`);\n    }\n    const id = String(list.id_str || list.id || '');\n    if (!/^\\d+$/.test(id)) {\n        throw new CommandExecutionError('CreateList returned a list payload without a numeric list id.');\n    }\n    if (typeof list.name !== 'string' || !list.name.trim()) {\n        throw new CommandExecutionError('CreateList returned a list payload without a list name.');\n    }\n    if (list.name.trim() !== expectedName) {\n        throw new CommandExecutionError(`CreateList returned name ${JSON.stringify(list.name)}, expected ${JSON.stringify(expectedName)}.`);","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-create.js#L34-L70","documentation":"This CommandExecutionError is thrown by requireCreateListResult in clis/twitter/list-create.js:52 when the CreateList response had HTTP ok status, but the body could not be parsed as JSON (or parsed to a non-object). The library validates result.bodyJson because every later check (data.list, errors) depends on a parsed object. The first 300 chars of the raw body are included to aid diagnosis.","triggerScenarios":"Twitter returns HTTP 2xx but with a non-JSON body: an HTML error/interstitial page (e.g. anti-bot challenge or maintenance page served with 200), an empty body, or a truncated response captured by page.evaluate.","commonSituations":"x.com serving a login/challenge HTML page with 200 status instead of JSON; Twitter maintenance windows returning HTML; proxy/VPN injecting content; network interruption truncating the response so JSON.parse fails.","solutions":["Inspect the embedded Body snippet — if it is HTML, you are being served a web page (challenge/maintenance) instead of the API response.","Re-authenticate the browser session on x.com so Twitter serves API JSON rather than a challenge page.","Disable or change proxy/VPN settings that may inject or truncate response bodies.","Retry after a delay if Twitter is under maintenance or degraded.","If it recurs, update the automation/browser environment so fetch from page context returns the real API payload."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// After the call, validate the payload shape before using it:\nfunction hasParseableJsonResult(result) {\n  return Boolean(result && result.ok && result.bodyJson && typeof result.bodyJson === 'object');\n}","typeGuard":"function isParsedJsonObject(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const row = await opencli twitter list-create name;\n} catch (err) {\n  if (/malformed JSON payload/.test(err.message)) {\n    // body was HTML/empty — re-auth session or retry; do not parse err.message further\n    await refreshXSession();\n  } else throw err;\n}","preventionTips":["Keep the automation browser session authenticated so x.com does not serve challenge/maintenance HTML with 200","Avoid proxies/VPNs that may inject or truncate response bodies","Retry transiently — a single malformed body is often a degraded-backend blip","Check status.x.com before running bulk list operations"],"tags":["json","twitter","response-parsing","graphql"],"backgroundTag":"malformed-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}