jackwener/OpenCLI · error · EmptyResultError
devto/${id}
Error message
devto/${id} What it means
EmptyResultError is thrown by `devto read` when the DEV.to API responds successfully but returns no article object for the requested id (fetchArticle returned null/undefined or an object lacking an `id`). The library treats an unidentifiable article as an empty result rather than a crash. It means the id was numeric/format-valid but the article does not exist or is not visible.
Source
Thrown at clis/devto/read.js:77
description: 'Read a DEV.to article body by id',
domain: 'dev.to',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'id', required: true, positional: true, help: 'DEV.to article id (numeric, e.g. 3605688)' },
{ name: 'max-length', type: 'int', default: 20000, help: 'Max characters of body to return (min 100)' },
],
columns: ['id', 'title', 'author', 'reactions', 'reading_time', 'tags', 'published_at', 'body', 'url'],
func: async (args) => {
const id = String(args.id || '').trim();
if (!/^\d+$/.test(id)) {
throw new ArgumentError(`Invalid DEV.to article id: ${args.id}`, 'Pass a numeric id like 3605688');
}
const maxLength = requireMinInt(args['max-length'] ?? 20000, 100, 'devto read --max-length');
const article = await fetchArticle(id);
if (!article || !article.id) {
throw new EmptyResultError(`devto/${id}`, 'Article not found');
}
const body = requireArticleBody(article, id);
const truncated = body.length > maxLength
? body.slice(0, maxLength) + '\n\n... [truncated]'
: body;
// The single-article endpoint returns `tag_list` as a comma-separated
// string and `tags` as an array — the opposite of the listing endpoints.
// Normalize either shape into a single comma-separated string.
const tagsRaw = article.tag_list ?? article.tags ?? '';
const tags = Array.isArray(tagsRaw) ? tagsRaw.join(', ') : String(tagsRaw);
return [{
id: article.id,
title: article.title || '',
author: article.user?.username || '[deleted]',
reactions: article.public_reactions_count ?? 0,View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the id is a real published DEV.to article (open dev.to and confirm the URL /<author>/<slug> maps to that id).
- Re-run the command to rule out a transient API failure, and check DEV.to API availability/rate limits.
- If you scraped the id earlier, re-fetch the article list to get the current id (deleted articles keep their id forever unreachable).
- Call the DEV.to API directly (curl https://dev.to/api/articles/<id>) to confirm it 404s before debugging the CLI.
Example fix
// before
await cli.devto.read({ id: 3605688 });
// after
const res = await fetch(`https://dev.to/api/articles/${id}`);
if (!res.ok) { console.warn(`article ${id} unavailable (${res.status})`); return; }
await cli.devto.read({ id }); Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch(`https://dev.to/api/articles/${id}`);
if (res.ok) { const a = await res.json(); if (a?.id) { /* safe to proceed */ } } Type guard
function isArticle(a) { return !!a && typeof a === 'object' && typeof a.id === 'number'; } Try / catch
try { await cli.devto.read({ id }); }
catch (e) { if (e.name === 'EmptyResultError') { console.warn(`article ${id} not found`); return null; } throw e; } Prevention
- Validate the id is numeric before calling (matches the CLI's own ArgumentError for non-numeric ids).
- Probe dev.to/api/articles/<id> once and cache known-good ids.
- Handle deleted/unpublished articles as a normal empty case, not a crash.
- Watch for DEV.to rate limiting which can surface as empty responses.
When it happens
Trigger: Running `devto read <numericId>` where the id does not correspond to any published article, the article was deleted/unpublished, or the API request failed silently and returned an empty body.
Common situations: Typo in a copied article id; article taken down by its author; DEV.to API returning an error object or empty payload (rate limiting, private/hidden content) that fetchArticle maps to null.
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
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- archive search failed: HTTP ${resp.status}
- HTTP ${result.httpStatus} from /api/organizations
- coingecko derivatives returned HTTP ${resp.status}
- ${label} returned HTTP ${res.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/675d952a4304c47d.
Report an issue: GitHub.