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
- Verify the question id by opening https://stackoverflow.com/questions/<id> in a browser; if it 404s or is deleted, use a different id.
- Confirm the id comes from stackoverflow.com and not another Stack Exchange site (serverfault, superuser, etc.).
- Re-derive the id by running `stackoverflow search <terms>` and picking a question from the results.
- 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
- Extract ids only from stackoverflow.com/questions/<id> URLs, not other SE sites.
- Validate the id is numeric before calling.
- Handle EmptyResultError as a normal 'not found' outcome in scripts, not a crash.
- Re-check links from old data — SO questions do get deleted.
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
- No Lobste.rs stories found for domain "${domain}".
- No prices returned for train_no=${trainNo} ${fromStation.nam
- No 12306 stations match "${keyword}"
- Chess.com returned 404 for ${url}
- CoinGecko returned no category data.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8f42d00d38a5206e.
Report an issue: GitHub.