{"record":{"id":"61ff933fbd24320a","repo":"jackwener/OpenCLI","slug":"invalid-hn-item-id-args-id","errorCode":null,"errorMessage":"Invalid HN item id: ${args.id}","messagePattern":"Invalid HN item id: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/hackernews/read.js","lineNumber":91,"sourceCode":"    site: 'hackernews',\n    name: 'read',\n    access: 'read',\n    description: 'Read a Hacker News story and its comment tree',\n    domain: 'news.ycombinator.com',\n    strategy: Strategy.PUBLIC,\n    browser: false,\n    args: [\n        { name: 'id', required: true, positional: true, help: 'HN item ID (e.g. 39847301)' },\n        { name: 'limit', type: 'int', default: 25, help: 'Max top-level comments' },\n        { name: 'depth', type: 'int', default: 2, help: 'Max reply depth (1=no replies, 2=one level of replies, etc.)' },\n        { name: 'replies', type: 'int', default: 5, help: 'Max replies shown per comment at each level' },\n        { name: 'max-length', type: 'int', default: 2000, help: 'Max characters per comment body (min 100)' },\n    ],\n    columns: ['type', 'author', 'score', 'text'],\n    func: async (args) => {\n        const id = String(args.id || '').trim();\n        if (!/^\\d+$/.test(id)) {\n            throw new ArgumentError(`Invalid HN item id: ${args.id}`, 'Pass a numeric id like 39847301');\n        }\n        const limit = requirePositiveInt(args.limit ?? 25, 'hackernews read --limit');\n        const maxDepth = requirePositiveInt(args.depth ?? 2, 'hackernews read --depth');\n        const maxReplies = requirePositiveInt(args.replies ?? 5, 'hackernews read --replies');\n        const maxLength = requireMinInt(args['max-length'] ?? 2000, 100, 'hackernews read --max-length');\n\n        const story = await fetchItem(id);\n        if (!story || story.deleted || story.dead) {\n            throw new EmptyResultError(`hackernews/${id}`, 'Story not found, deleted, or dead');\n        }\n\n        const results = [];\n\n        // Story header row. text combines title + selftext (Ask/Show HN body) + external URL.\n        const storyBodyRaw = htmlToText(story.text || '');\n        const storyBody = storyBodyRaw.length > maxLength\n            ? storyBodyRaw.slice(0, maxLength) + '\\n... [truncated]'\n            : storyBodyRaw;","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/hackernews/read.js#L73-L109","documentation":"The `hackernews read` command requires its positional `id` argument to be a purely numeric HN item id (`/^\\d+$/`). If the id is missing, empty, or contains any non-digit character, it throws `ArgumentError` with the hint 'Pass a numeric id like 39847301'. This check runs before validation of other flags or any API call.","triggerScenarios":"Running `hackernews read` with no id, with a story URL or slug instead of a numeric id (e.g. `https://news.ycombinator.com/item?id=...` pasted whole), an id containing whitespace/letters (e.g. `39847301a`), or shell variables that expand to empty.","commonSituations":"Pasting a full HN link instead of just the item number; automations extracting ids with regex that captured trailing punctuation or HTML entities; quoting bugs in shell scripts yielding empty strings.","solutions":["Pass only the numeric item id, e.g. `opencli hackernews read 39847301`","If you have a full HN URL, extract the `id=` query parameter first (e.g. `${url##*id=}` in bash)","Quote shell variables (`\"$id\"`) and verify they are non-empty and all digits before invoking"],"exampleFix":"// before\nopencli hackernews read \"https://news.ycombinator.com/item?id=39847301\"\n// after\nopencli hackernews read 39847301","handlingStrategy":"validation","validationCode":"function extractHnId(input) {\n  const m = String(input).match(/id=(\\d+)/); // full HN URL form\n  const id = m ? m[1] : String(input).trim();\n  if (!/^\\d+$/.test(id)) throw new Error(`Not a numeric HN item id: ${input}`);\n  return id;\n}\nconst id = extractHnId(rawInput);","typeGuard":"function isHnItemId(v) {\n  return typeof v === 'string' && /^\\d+$/.test(v.trim());\n}","tryCatchPattern":"try {\n  await run(['opencli', 'hackernews', 'read', id]);\n} catch (e) {\n  if (String(e.message).startsWith('Invalid HN item id')) {\n    console.error(`Normalize input to bare digits; got: ${id}`);\n  } else throw e;\n}","preventionTips":["Never paste full news.ycombinator.com URLs — strip to the id= query param","Trim and quote shell variables so whitespace or empty expansion cannot leak into the argument","Keep ids as strings end-to-end; avoid JSON parsers that might mangle them"],"tags":["argument-error","cli","input-validation","hn-item-id"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}