{"record":{"id":"19ae4891d92635c9","repo":"jackwener/OpenCLI","slug":"createlist-returned-a-list-payload-without-a-list","errorCode":null,"errorMessage":"CreateList returned a list payload without a list name.","messagePattern":"CreateList returned a list payload without a list name\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-create.js","lineNumber":67,"sourceCode":"        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)}.`);\n    }\n    const modeValue = typeof list.mode === 'string' ? list.mode : '';\n    if (!modeValue) {\n        throw new CommandExecutionError('CreateList returned a list payload without list mode.');\n    }\n    const mode = /private/i.test(modeValue) ? 'private' : 'public';\n    if (mode !== expectedMode) {\n        throw new CommandExecutionError(`CreateList returned mode ${mode}, expected ${expectedMode}.`);\n    }\n    return { createdList: list, listId: id, listMode: mode };\n}\n\nexport function buildListCreateRow({ result, name, description, mode }) {\n    const { createdList, listId, listMode } = requireCreateListResult(result, name, mode);\n    return {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-create.js#L49-L85","documentation":"requireCreateListResult validates the JSON payload returned by Twitter's CreateList GraphQL endpoint before the CLI reports success. It throws when the response payload has no usable `name` string (missing, non-string, or whitespace-only). This guards against silently creating a row for a list whose display name Twitter did not echo back.","triggerScenarios":"POST to https://x.com/i/api/graphql/<queryId>/CreateList returns 200 but the list object lacks `name` or has name:\"\" — e.g. API contract drift, a partial/degraded response, or the evaluate() result being a non-shape object.","commonSituations":"Twitter changes the CreateList response shape; a proxy/auth layer returns an unexpected object; the caller passes a mock/stub payload without name during tests.","solutions":["Inspect the raw CreateList response JSON to see what shape Twitter actually returned","Update the payload parsing (or queryId/FEATURES) to match the current GraphQL response schema","Retry the create; if transient, re-run `twitter list-create`","Capture and report the full payload in CommandExecutionError for debugging"],"exampleFix":"// before\nconst list = result?.data?.create_list; // schema drift yields undefined fields\n// after\nconst list = result?.data?.create_list ?? result?.data?.list_create ?? result; // handle known schema variants","handlingStrategy":"validation","validationCode":"if (!result?.data?.create_list || typeof result.data.create_list.name !== 'string' || !result.data.create_list.name.trim()) {\n  throw new Error('CreateList payload missing name; refusing to proceed');\n}","typeGuard":"function hasListName(list) {\n  return !!list && typeof list === 'object' && typeof list.name === 'string' && list.name.trim().length > 0;\n}","tryCatchPattern":"try {\n  const row = buildListCreateRow({ result, name, description, mode });\n} catch (e) {\n  if (e instanceof CommandExecutionError) console.error('CreateList payload invalid:', e.message, JSON.stringify(result));\n  else throw e;\n}","preventionTips":["Log the raw CreateList response when validation fails","Pin the queryId/FEATURES and update deliberately when Twitter's schema changes","Write a fixture test asserting the parser handles the current response shape"],"tags":["api-response","validation","twitter-graphql"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}