jackwener/OpenCLI · warning · EmptyResultError
No images found for illustration ${row.illust_id}.
Error message
No images found for illustration ${row.illust_id}. What it means
After confirming the pages payload is an array, prepareIllustPlan checks that at least one page exists. If the array is empty — the illustration has no downloadable pages — the CLI throws EmptyResultError('pixiv bookmark-download', ...) so the caller can treat it as an expected 'nothing found' outcome rather than a crash. This is a deliberate, structured empty-result signal, distinct from the malformed-payload error.
Source
Thrown at clis/pixiv/bookmark-download.js:58
throw new CommandExecutionError(`${label} returned a malformed image URL`);
}
const extension = path.extname(url.pathname).toLowerCase();
const contentType = IMAGE_CONTENT_TYPES.get(extension);
if (url.protocol !== 'https:' || url.hostname !== 'i.pximg.net' || url.username || url.password || url.port || !contentType) {
throw new CommandExecutionError(`${label} returned an untrusted Pixiv image URL`);
}
return { url: url.href, extension, contentType };
}
async function prepareIllustPlan(page, row, outputRoot) {
const pages = await pixivFetch(page, `/ajax/illust/${row.illust_id}/pages`, {
notFoundMsg: `Illustration not found: ${row.illust_id}`,
});
if (!Array.isArray(pages)) {
throw new CommandExecutionError('Pixiv pages API returned malformed payload');
}
if (pages.length === 0) {
throw new EmptyResultError('pixiv bookmark-download', `No images found for illustration ${row.illust_id}.`);
}
const files = pages.map((entry, index) => {
if (!entry || Array.isArray(entry) || typeof entry !== 'object' || !entry.urls || Array.isArray(entry.urls) || typeof entry.urls !== 'object') {
throw new CommandExecutionError(`Pixiv illustration ${row.illust_id} returned malformed page ${index + 1}`);
}
const parsed = parsePixivImageUrl(entry.urls.original || entry.urls.regular, `Pixiv illustration ${row.illust_id} page ${index + 1}`);
return {
...parsed,
filename: `${row.illust_id}_p${index}${parsed.extension}`,
};
});
const finalPath = path.join(outputRoot, 'illust', row.illust_id);
if (pixivPathEntryExists(finalPath)) {
throw new CommandExecutionError(`Refusing to overwrite existing Pixiv download: ${finalPath}`);
}
const createdDirs = [];
for (let cursor = path.dirname(finalPath); !fs.existsSync(cursor); cursor = path.dirname(cursor)) {
createdDirs.push(cursor);View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the illust_id directly in a browser while logged in; if the work is deleted/private, remove it from the bookmark set and re-run
- Disable R-18 filtering / safe mode on the account whose session the CLI uses, since filtered works return empty page lists
- Confirm the id is an illustration id (numeric illust_id, not user/novel id)
- Re-authenticate with fresh cookies — restricted-session responses can come back as empty arrays
- Wrap this expected case: catch EmptyResultError and skip/log the illustration instead of failing the whole run
Example fix
// before
await bookmarkDownload({ illustId: row.illust_id });
// after
try {
await bookmarkDownload({ illustId: row.illust_id });
} catch (err) {
if (err instanceof EmptyResultError) { console.warn(`skipped ${row.illust_id}: no images`); return; }
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that the work still exists and has pages before the run
const pages = await pixivFetch(page, `/ajax/illust/${row.illust_id}/pages`, {});
if (Array.isArray(pages) && pages.length === 0) console.warn(`illust ${row.illust_id} has no pages; skipping`); Type guard
function hasPages(pages) {
return Array.isArray(pages) && pages.length > 0;
} Try / catch
try {
await bookmarkDownload(row);
} catch (err) {
if (err instanceof EmptyResultError) {
console.warn(`${err.scope}: ${err.message} — skipping`); // expected outcome, not a failure
return;
}
throw err;
} Prevention
- Periodically prune bookmarks whose works have been deleted or made private
- Disable R-18 filtering/safe mode on the account used for downloads
- Check ids are valid illust ids (not user or novel ids) before running
- Treat EmptyResultError as a skip-able event in batch scripts rather than a hard failure
When it happens
Trigger: /ajax/illust/{illust_id}/pages returns [] — the illustration exists but exposes zero pages (e.g. works deleted/restricted after being bookmarked, R-18 works hidden by safe-mode/filter settings, or an id that resolves to an empty gallery).
Common situations: A bookmarked work was deleted or made private by the artist; Pixiv safe-search/filtering (R-18 filter) strips the page data; the wrong kind of id was passed (a user or novel id instead of an illust id) yielding an empty page list; regional or age-restricted content requiring different auth.
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
- nowcoder ${source}
- No Pixiv bookmarks matched the requested page.
- No images found for illustration ${illustId}.
- No Semantic Scholar citations for "${args.id}" at offset ${o
- No Semantic Scholar recommendations for "${args.id}".
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a7d8c7fe033e0b90.
Report an issue: GitHub.