jackwener/OpenCLI · error · EmptyResultError
Story not found
Error message
Story not found
What it means
This EmptyResultError is thrown by fetchStory (invoked by the `lobsters read` command) when GET https://lobste.rs/s/<shortId>.json returns HTTP 404, meaning no story exists with that short id on Lobste.rs. It distinguishes 'unknown/deleted story id' from transport failures, which raise CommandExecutionError instead.
Source
Thrown at clis/lobsters/read.js:23
* https://lobste.rs/s/<short_id>.json
* already returns the story plus a flat `comments[]` array where each entry
* carries `parent_comment` (short_id of parent or null) and `depth` — so we
* just need one HTTP call, then build a children map and DFS.
*
* Output rows:
* - first row is the story itself (`type=POST`)
* - each subsequent row is a comment, indented by depth (`L0`, `L1`, …)
* - `[+N more replies]` summary rows whenever depth/limit cuts in
*/
import { cli, Strategy } from '@jackwener/opencli/registry';
import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
const LOBSTERS_STORY_BASE = 'https://lobste.rs/s';
async function fetchStory(shortId) {
const res = await fetch(`${LOBSTERS_STORY_BASE}/${shortId}.json`);
if (res.status === 404) {
throw new EmptyResultError(`lobsters/${shortId}`, 'Story not found');
}
if (!res.ok) {
throw new CommandExecutionError(`Lobsters API HTTP ${res.status} for story ${shortId}`, 'Check the short id');
}
return res.json();
}
function requirePositiveInt(value, label) {
if (!Number.isInteger(value) || value <= 0) {
throw new ArgumentError(`${label} must be a positive integer`);
}
return value;
}
function requireMinInt(value, min, label) {
if (!Number.isInteger(value) || value < min) {
throw new ArgumentError(`${label} must be an integer >= ${min}`);
}View on GitHub (pinned to 49907e53dc)
Solutions
- Re-copy the short id from the story URL https://lobste.rs/s/<shortId> and verify it opens in a browser.
- Confirm the id comes from Lobste.rs, not another aggregator (HN/Reddit ids will not resolve).
- List stories again via `lobsters` front-page/domain commands to get a currently valid short id.
- In scripts, catch EmptyResultError and prompt the user to re-enter the id instead of crashing.
Example fix
// before
await cli.lobsters.read('12345678'); // HN-style numeric id -> Story not found
// after
const id = 'abcdefgh'; // copy from the lobste.rs story URL /s/<id>
await cli.lobsters.read(id); Defensive patterns
Strategy: validation
Validate before calling
function isValidLobstersShortId(id) {
return typeof id === 'string' && /^[a-z0-9]{5,10}$/i.test(id);
}
if (!isValidLobstersShortId(shortId)) {
console.error(`"${shortId}" does not look like a Lobste.rs short id (copy it from https://lobste.rs/s/<id>).`);
process.exit(1);
} Type guard
null
Try / catch
try {
const story = await cli.lobsters.read(shortId);
} catch (err) {
if (err.name === 'EmptyResultError') {
console.error(`No story with id "${shortId}" on Lobste.rs — check the id or the story may have been removed.`);
return;
}
throw err;
} Prevention
- Always copy short ids directly from lobste.rs story URLs (/s/<id>), never type them from memory.
- Do not use ids from other aggregators — Hacker News numeric ids will always 404 here.
- Re-fetch a fresh id list via front-page/domain commands if a previously valid id starts failing (story may have been deleted).
- Validate id shape (short alphanumeric string) before calling the read command in scripts.
When it happens
Trigger: Running `lobsters read <shortId>` where the id does not match any story: a typo in the short id, a story deleted or removed by moderators, an id copied from another site (Hacker News ids are numeric and will 404), or a truncated id.
Common situations: Hand-typing a short id from memory, using a HN numeric id like '12345678', referencing a story that was since deleted on lobste.rs, or off-by-one copy/paste of the id from a URL (extra characters or missing tail).
Related errors
- hf paper
- Unknown tag: ${value}
- Unknown category: ${value}
- Chess.com returned 404 for ${url}
- coingecko limit must be a positive integer
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2f994b663b92afee.
Report an issue: GitHub.