jackwener/OpenCLI · warning · EmptyResultError

hackernews/${id}

Error message

hackernews/${id}

What it means

`EmptyResultError` is thrown when the fetched HN item does not exist or has been removed: the Firebase API returns `null` for an unknown id, or the item carries `deleted: true` / `dead: true`. The error's resource is `hackernews/<id>` with hint 'Story not found, deleted, or dead'. This is an expected outcome for removed content, not a network failure.

Source

Thrown at clis/hackernews/read.js:100

        { 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;
        const storyParts = [story.title || ''];
        if (storyBody) storyParts.push('\n' + storyBody);
        if (story.url) storyParts.push('\n' + story.url);
        results.push({
            type: 'POST',
            author: story.by || '[deleted]',
            score: story.score ?? 0,
            text: storyParts.join('').trim(),
        });

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the id on huggingface — open https://news.ycombinator.com/item?id=<id> in a browser to confirm it exists
  2. Double-check digits of the id (off-by-one typos look valid numerically)
  3. If the story was deleted/dead, find an alternative source (e.g. a mirror or the Wayback Machine) — the CLI cannot return removed content

Example fix

// before
opencli hackernews read 398473011   // null item -> EmptyResultError
// after
opencli hackernews read 39847301    // live, valid story id
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check via the public Firebase API before invoking the CLI
const res = await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
const item = await res.json();
if (!item || item.deleted || item.dead) {
  console.warn(`HN item ${id} is missing/deleted/dead; skipping`);
}

Type guard

function isLiveStory(item) {
  return item != null && item.deleted !== true && item.dead !== true;
}

Try / catch

try {
  await run(['opencli', 'hackernews', 'read', id]);
} catch (e) {
  if (e.name === 'EmptyResultError' || String(e.message).includes('hackernews/')) {
    console.warn(`Story ${id} not found, deleted, or dead; skipping`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `hackernews read` with a numeric but nonexistent id (HN returns null); reading a story/comment that moderators killed or the author deleted; ids of items that were never stories (e.g. poll items are handled but some item types may be absent).

Common situations: Re-running scripts on ids saved weeks/months earlier whose stories were since deleted; typos in an otherwise valid numeric id (e.g. 398473011 vs 39847301); scraping archived lists containing dead HN posts.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/c242af7d958a9acf. Report an issue: GitHub.