{"record":{"id":"406dcb9ccb83b1bf","repo":"jackwener/OpenCLI","slug":"refusing-to-overwrite-existing-pixiv-download-d","errorCode":null,"errorMessage":"Refusing to overwrite existing Pixiv download: ${destPath}","messagePattern":"Refusing to overwrite existing Pixiv download: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/novel-download-utils.js","lineNumber":160,"sourceCode":"    `User ID: ${body.userId}`,\n    `Novel ID: ${body.id}`,\n    `URL: ${url}`,\n    body.createdDate ? `Created: ${body.createdDate}` : '',\n    tags ? `Tags: ${tags}` : '',\n    body.wordCount != null ? `Words: ${body.wordCount}` : '',\n    body.bookmarkCount != null ? `Bookmarks: ${body.bookmarkCount}` : '',\n    '',\n    body.content,\n    '',\n  ].filter(line => line !== '').join('\\n');\n}\n\nexport function prepareNovelFile(body, output, format) {\n  const outputDir = normalizePixivOutputRoot(output, './pixiv-downloads/novels');\n  const filename = `${body.id}.${format}`;\n  const destPath = path.join(outputDir, filename);\n  if (pixivPathEntryExists(destPath)) {\n    throw new CommandExecutionError(`Refusing to overwrite existing Pixiv download: ${destPath}`);\n  }\n  const createdDirs = [];\n  for (let cursor = outputDir; !fs.existsSync(cursor); cursor = path.dirname(cursor)) {\n    createdDirs.push(cursor);\n    if (path.dirname(cursor) === cursor) break;\n  }\n  return {\n    kind: 'novel',\n    outputDir,\n    createdDirs,\n    destPath,\n    content: formatNovelContent(body, format),\n  };\n}\n\nexport function writeNovelFile(body, output, format) {\n  return commitNovelFile(prepareNovelFile(body, output, format));\n}","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/novel-download-utils.js#L142-L178","documentation":"prepareNovelFile builds the destination <outputDir>/<novelId>.<format> and refuses to proceed if any filesystem entry (file, symlink, directory) already exists at that path (lstat succeeds). The download is deliberately non-destructive: existing Pixiv downloads are never overwritten, so the user gets a clear error instead of silent data loss.","triggerScenarios":"Downloading the same novel twice with the same --output and --format; a leftover partial or previously downloaded file with the same <id>.txt/<id>.md name; a directory named like the target file occupying the path.","commonSituations":"Re-running a batch script without cleaning the output folder; switching formats back and forth and re-downloading; restoring a backup over an existing tree; id collision from a shared download directory.","solutions":["Delete or move the existing file at the reported path if overwriting is intended, then re-run.","Use a different --output directory (or include date/batch in the path) for repeat runs.","Check pixivPathEntryExists yourself beforehand and skip or rename when the destination exists.","Clear stale partial downloads from crashed runs before retrying the batch."],"exampleFix":"// before\nawait writeNovelFile(body, './downloads'); // 12345.txt exists\n// after\nimport { pixivPathEntryExists } from './novel-download-utils.js';\nif (pixivPathEntryExists('./downloads/12345.txt')) {\n  console.log('already downloaded, skipping');\n} else {\n  await writeNovelFile(body, './downloads');\n}","handlingStrategy":"try-catch","validationCode":"import fs from 'node:fs';\nimport path from 'node:path';\nconst dest = path.join(outputDir, `${body.id}.${format}`);\nif (fs.existsSync(dest)) {\n  console.log(`Skipping ${dest}: already downloaded`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await downloadNovel(id, { output });\n} catch (e) {\n  if (e.message.startsWith('Refusing to overwrite existing Pixiv download')) {\n    console.log('Already downloaded — skipping.');\n  } else throw e;\n}","preventionTips":["Check for the existing destination before re-running a batch and skip it.","Use per-run output directories (date- or batch-suffixed) for repeat downloads.","Treat the error as a skip signal, not a crash, in batch scripts.","Clean up partial files from crashed runs to avoid stale collisions."],"tags":["filesystem","file-exists","no-overwrite","idempotency"],"backgroundTag":"file-already-exists","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}