jackwener/OpenCLI · error · CommandExecutionError

Pixiv image download failed: ${result?.error || 'invalid dow

Error message

Pixiv image download failed: ${result?.error || 'invalid download result'}

What it means

validateImageDownload verifies the result object returned by the image downloader: it must be an object with success === true, a positive safe-integer size, and the resolved URL/content type must match the expected file. If any of these fail, it throws CommandExecutionError 'Pixiv image download failed: <error or invalid download result>'. This catches failed, empty, or content-type-mismatched downloads before the plan is committed.

Source

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

      ...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);
    if (path.dirname(cursor) === cursor) break;
  }
  return { kind: 'illust', illustId: row.illust_id, finalPath, files, createdDirs };
}

function validateImageDownload(result, file) {
  if (!result || typeof result !== 'object' || result.success !== true || !Number.isSafeInteger(result.size) || result.size <= 0) {
    throw new CommandExecutionError(`Pixiv image download failed: ${result?.error || 'invalid download result'}`);
  }
  const final = parsePixivImageUrl(result.finalUrl, 'Pixiv image download');
  if (final.contentType !== file.contentType || result.contentType !== file.contentType) {
    throw new CommandExecutionError(`Pixiv image download returned unexpected content type for ${file.filename}`);
  }
}

async function commitIllustPlan(plan, cookies) {
  const parent = path.dirname(plan.finalPath);
  let staging;
  try {
    fs.mkdirSync(parent, { recursive: true });
    staging = fs.mkdtempSync(path.join(parent, `.opencli-${plan.illustId}-`));
    for (const file of plan.files) {
      const destination = path.join(staging, file.filename);
      const result = await httpDownload(file.url, destination, {
        cookies,
        headers: { Referer: 'https://www.pixiv.net/' },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read result.error from the thrown message to identify the actual failure (403/404/timeout etc.) and address that specific cause
  2. Ensure requests to i.pximg.net include the Referer: https://www.pixiv.net/ header — its absence commonly causes 403 download failures
  3. Refresh the Pixiv session/cookies and retry; CDN auth failures often stem from expired credentials
  4. Add a bounded retry with backoff around the download step for transient network errors
  5. Verify content-type/extension expectations; if Pixiv changed image formats, update parsePixivImageUrl handling

Example fix

// before
const result = await downloadImage(url, dest);
// after
async function downloadWithRetry(url, dest, attempts = 3) {
  for (let i = 1; i <= attempts; i++) {
    const result = await downloadImage(url, dest, { headers: { Referer: 'https://www.pixiv.net/' } });
    if (result?.success === true && Number.isSafeInteger(result.size) && result.size > 0) return result;
    if (i < attempts) await new Promise(r => setTimeout(r, 1000 * i));
  }
  throw new CommandExecutionError(`Pixiv image download failed after ${attempts} attempts`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate downloader contract expectations before committing the plan
function looksLikeValidDownload(result) {
  return !!result && typeof result === 'object' && result.success === true
    && Number.isSafeInteger(result.size) && result.size > 0
    && typeof result.finalUrl === 'string' && result.finalUrl.length > 0;
}

Type guard

function isValidImageDownload(result) {
  return typeof result === 'object' && result !== null
    && result.success === true
    && Number.isSafeInteger(result.size) && result.size > 0
    && typeof result.finalUrl === 'string'
    && typeof result.contentType === 'string';
}

Try / catch

try {
  await commitIllustPlan(plan);
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.startsWith('Pixiv image download failed')) {
    console.error(`download failed (${err.message}); will retry with backoff`);
    await retryPlan(plan); // retry transient CDN/network failures
  } else { throw err; }
}

Prevention

When it happens

Trigger: The downloader returns {success:false,error:...} (HTTP error, network failure, Pixiv 403/404 on the image CDN), or returns success with a non-positive/missing size, or null/undefined result ('invalid download result'), called from commitIllustPlan.

Common situations: Image CDN rejects the request due to missing Referer headers or expired session; the original URL 404s after Pixiv CDN rotation; a rate-limit or timeout produces success:false; a proxy returns a tiny HTML error page recorded as size 0.

Related errors


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