{"record":{"id":"4ab3ab667c6e4179","repo":"jackwener/OpenCLI","slug":"refusing-to-overwrite-existing-pixiv-download-f","errorCode":null,"errorMessage":"Refusing to overwrite existing Pixiv download: ${finalPath}","messagePattern":"Refusing to overwrite existing Pixiv download: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/bookmark-download.js","lineNumber":72,"sourceCode":"  if (!Array.isArray(pages)) {\n    throw new CommandExecutionError('Pixiv pages API returned malformed payload');\n  }\n  if (pages.length === 0) {\n    throw new EmptyResultError('pixiv bookmark-download', `No images found for illustration ${row.illust_id}.`);\n  }\n  const files = pages.map((entry, index) => {\n    if (!entry || Array.isArray(entry) || typeof entry !== 'object' || !entry.urls || Array.isArray(entry.urls) || typeof entry.urls !== 'object') {\n      throw new CommandExecutionError(`Pixiv illustration ${row.illust_id} returned malformed page ${index + 1}`);\n    }\n    const parsed = parsePixivImageUrl(entry.urls.original || entry.urls.regular, `Pixiv illustration ${row.illust_id} page ${index + 1}`);\n    return {\n      ...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}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/bookmark-download.js#L54-L90","documentation":"The computed destination directory outputRoot/illust/{illust_id} already exists on disk, so prepareIllustPlan refuses to re-download and overwrite it, throwing CommandExecutionError with the full path. This protects previously downloaded artwork from being clobbered by a re-run of the bookmark download.","triggerScenarios":"Running bookmark-download twice against the same bookmark set, or a previous run partially completed and left an illust/{id} directory behind, and pixivPathEntryExists(finalPath) therefore returns true.","commonSituations":"Re-running a cron/script without clearing the output directory; resuming an interrupted sync where the directory was created before files finished; pointing outputRoot at a location that already holds an older download of the same illustration.","solutions":["Delete or move the existing outputRoot/illust/{illust_id} directory if you want a fresh download","Use a different --output root for the new run so paths don't collide","Add a resume/skip mode: catch this error and treat existing directories as already-complete downloads","Check the existing directory's contents first — it may be a partial download you can complete manually instead of re-downloading"],"exampleFix":"// before\nawait bookmarkDownloadCli({ outputRoot: './downloads' });\n// after\nconst fs = require('fs');\nconst target = './downloads/illust/' + illustId;\nif (fs.existsSync(target)) { console.log('already downloaded, skipping'); } else { await bookmarkDownloadCli({ outputRoot: './downloads' }); }","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst path = require('path');\nconst finalPath = path.join(outputRoot, 'illust', row.illust_id);\nif (fs.existsSync(finalPath)) {\n  console.log(`skipping ${row.illust_id}: already exists at ${finalPath}`);\n  return;\n}","typeGuard":"function isSafeToDownload(outputRoot, illustId) {\n  const finalPath = require('path').join(outputRoot, 'illust', String(illustId));\n  return !require('fs').existsSync(finalPath);\n}","tryCatchPattern":"try {\n  await bookmarkDownload(row);\n} catch (err) {\n  if (err instanceof CommandExecutionError && err.message.startsWith('Refusing to overwrite existing Pixiv download')) {\n    console.warn(`${row.illust_id} already downloaded — skipping`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Give each run a fresh or versioned output root (e.g. output-YYYYMMDD) to avoid collisions","Build an idempotent runner that skips ids whose illust/{id} directory already exists","Inspect partial downloads after an interrupted run and complete or remove them before re-running","Archive/move old downloads rather than re-pointing outputRoot at the same tree"],"tags":["filesystem","conflict","idempotency"],"backgroundTag":"file-already-exists","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}