jackwener/OpenCLI · warning · EmptyResultError

Question not found

Error message

Question not found

What it means

EmptyResultError thrown by `stackoverflow read` when the Stack Exchange /questions/{id} endpoint returns a 200 envelope whose `items` array has no first element. The API does that instead of a 404 when a question id does not exist, was deleted, or is not visible to anonymous users. The CLI treats 'no items' as an empty result rather than a network failure, so the label tells you which lookup came back empty.

Source

Thrown at clis/stackoverflow/read.js:239

        { name: 'comments-limit', type: 'int', default: 5, help: 'Max comments per question/answer (1-100)' },
        { name: 'max-length', type: 'int', default: 4000, help: 'Max characters per body / answer / comment (min 100)' },
    ],
    columns: ['type', 'author', 'score', 'accepted', 'text'],
    func: async (args) => {
        const id = String(args.id || '').trim();
        if (!/^\d+$/.test(id)) {
            throw new ArgumentError(`Invalid Stack Overflow question id: ${args.id}`, 'Pass a numeric id like 79935770');
        }
        const answersLimit = requireBoundedInt(args['answers-limit'] ?? 10, 1, SE_MAX_PAGE_SIZE, 'stackoverflow read --answers-limit');
        const commentsLimit = requireBoundedInt(args['comments-limit'] ?? 5, 1, SE_MAX_PAGE_SIZE, 'stackoverflow read --comments-limit');
        const maxLength = requireMinInt(args['max-length'] ?? 4000, 100, 'stackoverflow read --max-length');

        const label = `stackoverflow/${id}`;
        const qUrl = `${SE_API_BASE}/questions/${id}?site=${SE_SITE}&filter=withbody`;
        const qData = await fetchJson(qUrl, label);
        const question = (qData.items || [])[0];
        if (!question) {
            throw new EmptyResultError(label, 'Question not found');
        }

        // Fetch question comments and answers in parallel.
        const [qCommentsData, answersData] = await Promise.all([
            fetchJson(
                `${SE_API_BASE}/questions/${id}/comments?site=${SE_SITE}&filter=withbody&order=asc&sort=creation&pagesize=${commentsLimit}`,
                `${label}/comments`,
            ),
            fetchJson(
                `${SE_API_BASE}/questions/${id}/answers?site=${SE_SITE}&filter=withbody&order=desc&sort=votes&pagesize=${answersLimit}`,
                `${label}/answers`,
            ),
        ]);

        const allAnswers = await fetchMissingAcceptedAnswer(question, answersData.items || [], label);
        // Surface accepted answer first, then by score order.
        const orderedAnswers = byAcceptedThenScoreDesc(question, allAnswers).slice(0, answersLimit);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the question id by opening https://stackoverflow.com/questions/<id> in a browser; if it 404s or is deleted, use a different id.
  2. Confirm the id comes from stackoverflow.com and not another Stack Exchange site (serverfault, superuser, etc.).
  3. Re-derive the id by running `stackoverflow search <terms>` and picking a question from the results.
  4. If you expect empty results sometimes, catch EmptyResultError in the calling script instead of treating it as a crash.

Example fix

// before: blindly reading a scraped id
await cli.run(['stackoverflow', 'read', scrapedId]);
// after: guard against non-numeric/absent ids and handle empty
if (!/^\d+$/.test(scrapedId ?? '')) return null;
try {
  return await cli.run(['stackoverflow', 'read', scrapedId]);
} catch (e) {
  if (e.name === 'EmptyResultError') return null;
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!/^\d+$/.test(String(id ?? '').trim())) throw new Error(`not a numeric question id: ${id}`);

Type guard

function isNumericId(v) { return typeof v === 'string' ? /^\d+$/.test(v.trim()) : Number.isInteger(v) && v > 0; }

Try / catch

try {
  const q = await read(id);
} catch (e) {
  if (e.name === 'EmptyResultError') {
    console.warn(`question ${id} not found or deleted`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `stackoverflow read <id>` where <id> is a nonexistent question id, a deleted question, a closed/removed post, or an id from a different Stack Exchange site (e.g. a Server Fault id against site=stackoverflow).

Common situations: Copying an id from a Stack Exchange site other than stackoverflow; the question was deleted by moderators after you got the link; a typo in the id (e.g. dropped/extra digit); agents scraping old references to questions that have since been removed.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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