{"record":{"id":"a04a2d0d130c31cd","repo":"jackwener/OpenCLI","slug":"draft-id-is-required","errorCode":null,"errorMessage":"Draft id is required","messagePattern":"Draft id is required","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/draft-utils.js","lineNumber":36,"sourceCode":"    ) {\n        return value.data;\n    }\n    return value;\n}\n\nexport function normalizeDraftType(value, { allowAll = false } = {}) {\n    const raw = String(value ?? 'image').trim().toLowerCase();\n    if (allowAll && raw === 'all') return raw;\n    if (!STORE_NAME_MAP[raw]) {\n        const choices = allowAll ? 'image, video, article, audio, all' : Object.keys(STORE_NAME_MAP).join(', ');\n        throw new ArgumentError(`Unsupported draft type \"${raw}\". Expected one of: ${choices}`);\n    }\n    return raw;\n}\n\nexport function normalizeDraftId(value) {\n    const id = String(value ?? '').trim();\n    if (!id) throw new ArgumentError('Draft id is required');\n    return id;\n}\n\nexport function encodeDraftKey(key) {\n    const type = typeof key;\n    if (type === 'string') return `s:${key}`;\n    if (type === 'number') return `n:${String(key)}`;\n    if (type === 'boolean') return `b:${String(key)}`;\n    try {\n        return `j:${encodeURIComponent(JSON.stringify(key))}`;\n    }\n    catch {\n        return `s:${String(key)}`;\n    }\n}\n\nexport function findDraftEntry(entries, id) {\n    return entries.find((entry) => encodeDraftKey(entry?.key) === id) || null;","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/draft-utils.js#L18-L54","documentation":"normalizeDraftId requires a non-empty draft id and throws ArgumentError when the value is missing, null, undefined, or only whitespace. The draft commands need an id to locate the specific record to inspect or delete.","triggerScenarios":"Invoking draft-delete (or similar) without --id, with --id=\"\", or with a value consisting only of spaces; passing a variable that is undefined because an earlier lookup step failed or returned nothing.","commonSituations":"Scripting the CLI where the id comes from a previous command's JSON output that was empty; quoting mistakes in shell leaving an empty argument; forgetting the --id flag entirely.","solutions":["Pass a concrete draft id via the --id flag (obtain it from the list/count command output)","Check that the upstream value producing the id is not empty/undefined before invoking","Trim shell variables: node draft-delete.js --id \"$ID\" with ID verified non-empty"],"exampleFix":"// before\nconst id = cfg.lastDraft?.id; // undefined\nawait draftDelete({ id }); // throws 'Draft id is required'\n// after\nif (!cfg.lastDraft?.id) throw new Error('No draft id in config; run draft list first');\nawait draftDelete({ id: cfg.lastDraft.id });","handlingStrategy":"validation","validationCode":"const id = String(opts.id ?? '').trim();\nif (!id) throw new Error('Provide a non-empty --id (see draft list output)');","typeGuard":"function hasDraftId(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  await draftDelete({ type: 'video', id, execute: true });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message === 'Draft id is required') {\n    console.error('Missing --id; run the list command to get draft ids');\n  } else throw e;\n}","preventionTips":["Always pass --id explicitly; never rely on possibly-undefined variables","Validate upstream data (previous command output) before using it as an id","Trim shell variables and check non-empty before interpolation","Fail fast in wrapper scripts when the id lookup step yields nothing"],"tags":["cli","argument-validation","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}