{"record":{"id":"b2339c2359a788f2","repo":"jackwener/OpenCLI","slug":"createlist-returned-a-list-payload-without-a-numer","errorCode":null,"errorMessage":"CreateList returned a list payload without a numeric list id.","messagePattern":"CreateList returned a list payload without a numeric list id\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-create.js","lineNumber":64,"sourceCode":"    }\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)}.`);\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","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-create.js#L46-L82","documentation":"This CommandExecutionError is thrown by requireCreateListResult in clis/twitter/list-create.js:64 when the returned list object exists but lacks an id that matches /^\\d+$/. Twitter list ids are numeric (id_str or id); the library requires one to hand back a usable listId. It protects callers from using a malformed or missing identifier.","triggerScenarios":"data.list present but both id_str and id are missing, null, non-numeric (e.g. a base64 GraphQL cursor-style id), or empty string — typically a response schema change or a partially populated list object.","commonSituations":"Twitter changing CreateList to return a different id field name or format; a mock/test server returning a stub list without numeric ids; future GraphQL versions returning string-encoded ids instead of numeric id_str.","solutions":["Log/inspect the full list payload (the error deliberately omits it) to see which id fields Twitter actually returned.","If Twitter changed the field name/format, update the extraction in clis/twitter/list-create.js:62 (currently `list.id_str || list.id`) to the new field.","Verify you are talking to the real x.com API and not a stub/mock environment returning non-numeric ids.","Check whether the list exists on x.com and, if created, retrieve its numeric id from the UI or a ListLatest/ListByRequest query.","Retry creation only after confirming no list was actually created, to avoid duplicates."],"exampleFix":"// before\nconst id = String(list.id_str || list.id || '');\n// after (if Twitter adds a new id field)\nconst id = String(list.id_str || list.id || list.rest_id || '');","handlingStrategy":"type-guard","validationCode":"// Guard the id fields before trusting the returned list id:\nfunction hasNumericListId(list) {\n  const id = String(list?.id_str || list?.id || '');\n  return /^\\d+$/.test(id);\n}","typeGuard":"function hasNumericListId(list) {\n  const raw = list && (list.id_str ?? list.id);\n  return typeof raw === 'string' || typeof raw === 'number'\n    ? /^\\d+$/.test(String(raw))\n    : false;\n}","tryCatchPattern":"try {\n  const row = await opencli twitter list-create name;\n} catch (err) {\n  if (/without a numeric list id/.test(err.message)) {\n    // inspect the raw payload / verify the list on x.com; do not use a fabricated id\n    reportFatal('CreateList returned a list without a usable numeric id');\n  } else throw err;\n}","preventionTips":["Only trust numeric ids (id_str/id) from CreateList; never persist cursor-style or encoded ids as list identifiers","Update the id extraction path promptly if Twitter renames or reformats the id field","Test against the real x.com API — mock servers returning stub ids will trip this guard","Verify on x.com whether the list exists before re-running creation to avoid duplicates"],"tags":["twitter","schema-change","validation","graphql"],"backgroundTag":"missing-api-response-field","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}