{"record":{"id":"ceeb84193efc8d1c","repo":"jackwener/OpenCLI","slug":"pixiv-image-download-failed-result-error-i","errorCode":null,"errorMessage":"Pixiv image download failed: ${result?.error || 'invalid download result'}","messagePattern":"Pixiv image download failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/bookmark-download.js","lineNumber":84,"sourceCode":"      ...parsed,\n      filename: `${row.illust_id}_p${index}${parsed.extension}`,\n    };\n  });\n  const finalPath = path.join(outputRoot, 'illust', row.illust_id);\n  if (pixivPathEntryExists(finalPath)) {\n    throw new CommandExecutionError(`Refusing to overwrite existing Pixiv download: ${finalPath}`);\n  }\n  const createdDirs = [];\n  for (let cursor = path.dirname(finalPath); !fs.existsSync(cursor); cursor = path.dirname(cursor)) {\n    createdDirs.push(cursor);\n    if (path.dirname(cursor) === cursor) break;\n  }\n  return { kind: 'illust', illustId: row.illust_id, finalPath, files, createdDirs };\n}\n\nfunction validateImageDownload(result, file) {\n  if (!result || typeof result !== 'object' || result.success !== true || !Number.isSafeInteger(result.size) || result.size <= 0) {\n    throw new CommandExecutionError(`Pixiv image download failed: ${result?.error || 'invalid download result'}`);\n  }\n  const final = parsePixivImageUrl(result.finalUrl, 'Pixiv image download');\n  if (final.contentType !== file.contentType || result.contentType !== file.contentType) {\n    throw new CommandExecutionError(`Pixiv image download returned unexpected content type for ${file.filename}`);\n  }\n}\n\nasync function commitIllustPlan(plan, cookies) {\n  const parent = path.dirname(plan.finalPath);\n  let staging;\n  try {\n    fs.mkdirSync(parent, { recursive: true });\n    staging = fs.mkdtempSync(path.join(parent, `.opencli-${plan.illustId}-`));\n    for (const file of plan.files) {\n      const destination = path.join(staging, file.filename);\n      const result = await httpDownload(file.url, destination, {\n        cookies,\n        headers: { Referer: 'https://www.pixiv.net/' },","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/bookmark-download.js#L66-L102","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read result.error from the thrown message to identify the actual failure (403/404/timeout etc.) and address that specific cause","Ensure requests to i.pximg.net include the Referer: https://www.pixiv.net/ header — its absence commonly causes 403 download failures","Refresh the Pixiv session/cookies and retry; CDN auth failures often stem from expired credentials","Add a bounded retry with backoff around the download step for transient network errors","Verify content-type/extension expectations; if Pixiv changed image formats, update parsePixivImageUrl handling"],"exampleFix":"// before\nconst result = await downloadImage(url, dest);\n// after\nasync function downloadWithRetry(url, dest, attempts = 3) {\n  for (let i = 1; i <= attempts; i++) {\n    const result = await downloadImage(url, dest, { headers: { Referer: 'https://www.pixiv.net/' } });\n    if (result?.success === true && Number.isSafeInteger(result.size) && result.size > 0) return result;\n    if (i < attempts) await new Promise(r => setTimeout(r, 1000 * i));\n  }\n  throw new CommandExecutionError(`Pixiv image download failed after ${attempts} attempts`);\n}","handlingStrategy":"try-catch","validationCode":"// Validate downloader contract expectations before committing the plan\nfunction looksLikeValidDownload(result) {\n  return !!result && typeof result === 'object' && result.success === true\n    && Number.isSafeInteger(result.size) && result.size > 0\n    && typeof result.finalUrl === 'string' && result.finalUrl.length > 0;\n}","typeGuard":"function isValidImageDownload(result) {\n  return typeof result === 'object' && result !== null\n    && result.success === true\n    && Number.isSafeInteger(result.size) && result.size > 0\n    && typeof result.finalUrl === 'string'\n    && typeof result.contentType === 'string';\n}","tryCatchPattern":"try {\n  await commitIllustPlan(plan);\n} catch (err) {\n  if (err instanceof CommandExecutionError && err.message.startsWith('Pixiv image download failed')) {\n    console.error(`download failed (${err.message}); will retry with backoff`);\n    await retryPlan(plan); // retry transient CDN/network failures\n  } else { throw err; }\n}","preventionTips":["Always send Referer: https://www.pixiv.net/ when fetching i.pximg.net image URLs","Keep the Pixiv session fresh; expired cookies cause CDN 403s","Add bounded retry/backoff around individual image downloads for transient errors","Check result.error in the message first — it names the underlying HTTP/network cause","Verify disk space and permissions so downloads aren't truncated to size 0"],"tags":["network","download","retry"],"backgroundTag":"download-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}