{"record":{"id":"7763f2c44873aef5","repo":"jackwener/OpenCLI","slug":"invalid-lobsters-short-id-args-id","errorCode":null,"errorMessage":"Invalid Lobsters short_id: ${args.id}","messagePattern":"Invalid Lobsters short_id: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/lobsters/read.js","lineNumber":100,"sourceCode":"    site: 'lobsters',\n    name: 'read',\n    access: 'read',\n    description: 'Read a Lobste.rs story and its comment tree',\n    domain: 'lobste.rs',\n    strategy: Strategy.PUBLIC,\n    browser: false,\n    args: [\n        { name: 'id', required: true, positional: true, help: 'Lobste.rs short_id (e.g. 6cmh6h)' },\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 shortId = String(args.id || '').trim();\n        if (!/^[a-z0-9]+$/.test(shortId)) {\n            throw new ArgumentError(`Invalid Lobsters short_id: ${args.id}`, 'Pass a lowercase alphanumeric id like 6cmh6h');\n        }\n        const limit = requirePositiveInt(args.limit ?? 25, 'lobsters read --limit');\n        const maxDepth = requirePositiveInt(args.depth ?? 2, 'lobsters read --depth');\n        const maxReplies = requirePositiveInt(args.replies ?? 5, 'lobsters read --replies');\n        const maxLength = requireMinInt(args['max-length'] ?? 2000, 100, 'lobsters read --max-length');\n\n        const story = await fetchStory(shortId);\n        if (!story || !story.short_id) {\n            throw new EmptyResultError(`lobsters/${shortId}`, 'Story not found');\n        }\n\n        const results = [];\n\n        // Story header — title, body (description_plain, often empty for link posts), then external url.\n        const storyBodyRaw = (story.description_plain || htmlToText(story.description || '')).trim();\n        const storyBody = storyBodyRaw.length > maxLength\n            ? storyBodyRaw.slice(0, maxLength) + '\\n... [truncated]'\n            : storyBodyRaw;","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lobsters/read.js#L82-L118","documentation":"Thrown at clis/lobsters/read.js:100 before any HTTP call when the positional id argument doesn't match /^[a-z0-9]+$/ — the format of Lobsters short ids (e.g. '6cmh6h'). ArgumentError means the input was malformed so fetching would be pointless; the hint suggests a lowercase alphanumeric id.","triggerScenarios":"`lobsters read 'https://lobste.rs/s/6cmh6h'` (full URL instead of id), uppercase ids like '6CMH6H', ids containing punctuation, empty string, or whitespace-only input.","commonSituations":"Pasting the full story URL from a browser instead of the slug; copying an id from an HN-style link with extra characters; quoting issues in shells leaving trailing spaces; using an uppercase variant of a valid id.","solutions":["Extract just the slug: for https://lobste.rs/s/6cmh6h use 6cmh6h","Lowercase the id before passing (ids are lowercase alphanumeric only)","Trim whitespace/quotes from the value","Pre-validate in scripts: /^[a-z0-9]+$/.test(id) before invoking"],"exampleFix":"// before\nconst id = 'https://lobste.rs/s/6cmh6h';\n// after\nconst id = 'https://lobste.rs/s/6cmh6h'.split('/s/')[1] || '';\n// => '6cmh6h'","handlingStrategy":"validation","validationCode":"const shortId = String(rawId || '').trim().toLowerCase();\nif (!/^[a-z0-9]+$/.test(shortId)) {\n  throw new Error(`Invalid Lobsters short_id: ${rawId}`);\n}","typeGuard":"function isValidLobstersId(v) {\n  return typeof v === 'string' && /^[a-z0-9]+$/.test(v.trim());\n}","tryCatchPattern":"try {\n  return await readLobstersStory(rawId);\n} catch (e) {\n  if (e.message.startsWith('Invalid Lobsters short_id')) {\n    const m = String(rawId).match(/\\/s\\/([a-z0-9]+)/i);\n    if (m) return readLobstersStory(m[1].toLowerCase());\n  }\n  throw e;\n}","preventionTips":["Always pass the bare slug, not the full URL","Normalize: trim + toLowerCase before passing","Derive the id with /lobste\\.rs\\/s\\/([a-z0-9]+)/ when given a URL","Validate with the same regex the CLI uses before calling"],"tags":["validation","cli-arguments","input-error"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}