jackwener/OpenCLI · error · ArgumentError
Invalid HN item id: ${args.id}
Error message
Invalid HN item id: ${args.id} What it means
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.
Source
Thrown at clis/hackernews/read.js:91
site: 'hackernews',
name: 'read',
access: 'read',
description: 'Read a Hacker News story and its comment tree',
domain: 'news.ycombinator.com',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'id', required: true, positional: true, help: 'HN item ID (e.g. 39847301)' },
{ name: 'limit', type: 'int', default: 25, help: 'Max top-level comments' },
{ name: 'depth', type: 'int', default: 2, help: 'Max reply depth (1=no replies, 2=one level of replies, etc.)' },
{ name: 'replies', type: 'int', default: 5, help: 'Max replies shown per comment at each level' },
{ name: 'max-length', type: 'int', default: 2000, help: 'Max characters per comment body (min 100)' },
],
columns: ['type', 'author', 'score', 'text'],
func: async (args) => {
const id = String(args.id || '').trim();
if (!/^\d+$/.test(id)) {
throw new ArgumentError(`Invalid HN item id: ${args.id}`, 'Pass a numeric id like 39847301');
}
const limit = requirePositiveInt(args.limit ?? 25, 'hackernews read --limit');
const maxDepth = requirePositiveInt(args.depth ?? 2, 'hackernews read --depth');
const maxReplies = requirePositiveInt(args.replies ?? 5, 'hackernews read --replies');
const maxLength = requireMinInt(args['max-length'] ?? 2000, 100, 'hackernews read --max-length');
const story = await fetchItem(id);
if (!story || story.deleted || story.dead) {
throw new EmptyResultError(`hackernews/${id}`, 'Story not found, deleted, or dead');
}
const results = [];
// Story header row. text combines title + selftext (Ask/Show HN body) + external URL.
const storyBodyRaw = htmlToText(story.text || '');
const storyBody = storyBodyRaw.length > maxLength
? storyBodyRaw.slice(0, maxLength) + '\n... [truncated]'
: storyBodyRaw;View on GitHub (pinned to 49907e53dc)
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
Example fix
// before opencli hackernews read "https://news.ycombinator.com/item?id=39847301" // after opencli hackernews read 39847301
Defensive patterns
Strategy: validation
Validate before calling
function extractHnId(input) {
const m = String(input).match(/id=(\d+)/); // full HN URL form
const id = m ? m[1] : String(input).trim();
if (!/^\d+$/.test(id)) throw new Error(`Not a numeric HN item id: ${input}`);
return id;
}
const id = extractHnId(rawInput); Type guard
function isHnItemId(v) {
return typeof v === 'string' && /^\d+$/.test(v.trim());
} Try / catch
try {
await run(['opencli', 'hackernews', 'read', id]);
} catch (e) {
if (String(e.message).startsWith('Invalid HN item id')) {
console.error(`Normalize input to bare digits; got: ${id}`);
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.
Related errors
- coingecko derivatives limit must be a positive integer
- --from and --to must differ (got ${fromCity})
- ${label} must be a positive integer
- ${label} must be an integer >= ${min}
- thread-or-recipient is required
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/61ff933fbd24320a.
Report an issue: GitHub.