{"record":{"id":"d029fb328191d2aa","repo":"jackwener/OpenCLI","slug":"pixiv-illustration-plan-illustid-download-faile","errorCode":null,"errorMessage":"Pixiv illustration ${plan.illustId} download failed: ${error?.message || error}","messagePattern":"Pixiv illustration (.+?) download failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/bookmark-download.js","lineNumber":125,"sourceCode":"      const stat = fs.lstatSync(destination);\n      if (stat.isSymbolicLink() || !stat.isFile() || stat.size <= 0) {\n        throw new CommandExecutionError(`Pixiv image download did not create a valid file: ${file.filename}`);\n      }\n    }\n    if (pixivPathEntryExists(plan.finalPath)) {\n      throw new CommandExecutionError(`Refusing to overwrite existing Pixiv download: ${plan.finalPath}`);\n    }\n    fs.renameSync(staging, plan.finalPath);\n    return plan.finalPath;\n  } catch (error) {\n    if (staging) {\n      try { fs.rmSync(staging, { recursive: true, force: true }); } catch {}\n    }\n    for (const directory of plan.createdDirs) {\n      try { fs.rmdirSync(directory); } catch {}\n    }\n    if (error instanceof CommandExecutionError) throw error;\n    throw new CommandExecutionError(`Pixiv illustration ${plan.illustId} download failed: ${error?.message || error}`);\n  }\n}\n\nfunction cleanupPlan(plan) {\n  if (plan.kind === 'novel') {\n    cleanupNovelFile(plan);\n    return;\n  }\n  try { fs.rmSync(plan.finalPath, { recursive: true, force: true }); } catch {}\n  for (const directory of plan.createdDirs) {\n    try { fs.rmdirSync(directory); } catch {}\n  }\n}\n\ncli({\n  site: 'pixiv',\n  name: 'bookmark-download',\n  access: 'read',","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/bookmark-download.js#L107-L143","documentation":"commitIllustPlan wraps its whole staging/commit work in try/catch; any failure that is not already a CommandExecutionError (rename failures, permission errors, network errors from the downloader, fs errors) is re-thrown as this generic per-illustration error carrying the illustId. Already-typed CommandExecutionErrors pass through unchanged. The staging directory and any created directories are cleaned up before throwing.","triggerScenarios":"Any exception inside commitIllustPlan other than a CommandExecutionError — e.g. fetch/failure from the Pixiv download call, fs.renameSync/lstatSync/rmSync throwing (ENOENT, EACCES, EBUSY), or any third-party library error during file staging.","commonSituations":"Network interruption mid-image download; the pixiv page/session expired so the download call rejects; output disk full or read-only; filesystem error moving the staged file into place; unexpected null/undefined dereferenced inside the commit path.","solutions":["Read the inner error.message in the message to identify the root cause (network vs filesystem vs auth)","Re-run the download for that illustId after confirming the network and Pixiv session are healthy","Check permissions and free space on the output/staging directories","Re-login/refresh Pixiv cookies if the inner message indicates an authentication or page fetch problem","Wrap known failure points in typed CommandExecutionErrors if you need finer-grained handling"],"exampleFix":"// before: opaque error, cause lost\nthrow new CommandExecutionError(`Pixiv illustration ${plan.illustId} download failed: ${error?.message || error}`);\n// after: preserve the original error for debugging\nconst wrapped = new CommandExecutionError(`Pixiv illustration ${plan.illustId} download failed: ${error?.message || error}`);\nwrapped.cause = error;\nthrow wrapped;","handlingStrategy":"try-catch","validationCode":"if (!plan || !plan.illustId || !Array.isArray(plan.files)) {\n  throw new Error('invalid illust plan before commit');\n}","typeGuard":"function isCommandExecutionError(e) {\n  return e instanceof Error && e.constructor.name === 'CommandExecutionError';\n}","tryCatchPattern":"try {\n  await commitIllustPlan(plan, cookies);\n} catch (err) {\n  console.error(`Illustration ${plan.illustId} failed: ${err.message}`);\n  failedIds.push(plan.illustId); // continue with the rest, retry later\n}","preventionTips":["Read the inner error.message first — this error wraps the real cause","Verify network, cookies and disk space before large runs","Retry individual failed illustIds rather than the whole archive","Keep staging directories writable and on the same filesystem as the output"],"tags":["pixiv","download","wrapper-error","filesystem"],"backgroundTag":"download-failed-wrapped","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}