jackwener/OpenCLI · error · CommandExecutionError

${label} returned a missing image URL

Error message

${label} returned a missing image URL

What it means

This CommandExecutionError is thrown by parsePixivImageUrl in clis/pixiv/bookmark-download.js:32-35 when a Pixiv API payload yields no usable image URL. The value passed in (entry.urls.original or entry.urls.regular, per prepareIllustPlan) is not a non-empty string, meaning the API response lacks the expected URL field.

Source

Thrown at clis/pixiv/bookmark-download.js:34

} from './novel-download-utils.js';

const IMAGE_CONTENT_TYPES = new Map([
  ['.jpg', 'image/jpeg'],
  ['.jpeg', 'image/jpeg'],
  ['.png', 'image/png'],
  ['.gif', 'image/gif'],
  ['.webp', 'image/webp'],
]);

function requireExecute(value) {
  if (value !== true) {
    throw new ArgumentError('Refusing to write local Pixiv downloads: pass --execute');
  }
}

function parsePixivImageUrl(value, label) {
  if (typeof value !== 'string' || !value) {
    throw new CommandExecutionError(`${label} returned a missing image URL`);
  }
  let url;
  try {
    url = new URL(value);
  } catch {
    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}`,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate the pixiv session (run the pixiv auth flow) — restricted or expired sessions often yield incomplete payloads
  2. Check the illustration is publicly accessible (not deleted, R-18-gated, or limited to my-pixiv watchers)
  3. Log the raw /ajax/illust/<id>/pages response to confirm the urls field shape and compare against the current Pixiv API schema
  4. Skip the offending illustration or update the CLI's URL extraction to match a changed API response format
Defensive patterns

Strategy: validation

Validate before calling

function hasImageUrl(entry) {
  const u = entry && entry.urls;
  return u && typeof u === 'object' &&
    ((typeof u.original === 'string' && u.original) ||
     (typeof u.regular === 'string' && u.regular));
}
if (!hasImageUrl(pageEntry)) {
  console.warn('Skipping page with no image URL:', pageEntry);
}

Type guard

function isNonEmptyString(v) {
  return typeof v === 'string' && v.length > 0;
}

Try / catch

try {
  const parsed = parsePixivImageUrl(entry.urls.original || entry.urls.regular, label);
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('missing image URL')) {
    console.warn(`${label}: no URL in API response — check auth/permissions for this illust`);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: The /ajax/illust/<id>/pages response contains a page entry whose urls object has neither original nor regular, or both are empty/non-string, so parsePixivImageUrl receives undefined/null/'' at clis/pixiv/bookmark-download.js:33.

Common situations: Pixiv changed the /ajax/illust pages response schema; the illustration is restricted (R-18, my-pixiv-only, or deleted) so Pixiv returns a payload without image URLs; an unauthenticated/expired session causes degraded API responses; region-restricted works return empty url fields.

Related errors


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