jackwener/OpenCLI · error · CommandExecutionError

Refusing to overwrite existing Pixiv download: ${plan.finalP

Error message

Refusing to overwrite existing Pixiv download: ${plan.finalPath}

What it means

commitIllustPlan refuses to clobber an existing path: before renaming the staged download into place it checks pixivPathEntryExists(plan.finalPath). This CommandExecutionError is thrown when a file or directory already exists at the final destination, protecting prior downloads from silent overwrite. The whole illustration is rolled back (staging removed, created dirs cleaned).

Source

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

  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/' },
        timeout: 60000,
        includeContentType: true,
      });
      validateImageDownload(result, file);
      const stat = fs.lstatSync(destination);
      if (stat.isSymbolicLink() || !stat.isFile() || stat.size <= 0) {
        throw new CommandExecutionError(`Pixiv image download did not create a valid file: ${file.filename}`);
      }
    }
    if (pixivPathEntryExists(plan.finalPath)) {
      throw new CommandExecutionError(`Refusing to overwrite existing Pixiv download: ${plan.finalPath}`);
    }
    fs.renameSync(staging, plan.finalPath);
    return plan.finalPath;
  } catch (error) {
    if (staging) {
      try { fs.rmSync(staging, { recursive: true, force: true }); } catch {}
    }
    for (const directory of plan.createdDirs) {
      try { fs.rmdirSync(directory); } catch {}
    }
    if (error instanceof CommandExecutionError) throw error;
    throw new CommandExecutionError(`Pixiv illustration ${plan.illustId} download failed: ${error?.message || error}`);
  }
}

function cleanupPlan(plan) {
  if (plan.kind === 'novel') {
    cleanupNovelFile(plan);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use a fresh or empty --output directory for the run
  2. Delete or move the existing file at plan.finalPath if you intend to re-download it
  3. Skip artworks whose files already exist before building the plan
  4. Avoid running two bookmark-download processes concurrently against the same output root
  5. Check for orphaned partial downloads from previous failed runs

Example fix

// before: unconditional re-run into same dir
pixiv bookmark-download --page 1 --output ./pixiv-downloads/bookmarks
// after: check first, then download only missing items
for f in wantedIds; do [ -e "out/$f.jpg" ] || pixiv bookmark-download --page 1 --output ./pixiv-downloads/bookmarks; done
Defensive patterns

Strategy: validation

Validate before calling

if (fs.existsSync(plan.finalPath)) {
  console.warn(`Skipping existing download: ${plan.finalPath}`);
  return plan.finalPath;
}

Type guard

function isFreeForWrite(p) {
  return !fs.existsSync(p) && !fs.existsSync(p + '.part');
}

Try / catch

try {
  return commitIllustPlan(plan, cookies);
} catch (err) {
  if (/Refusing to overwrite/.test(err.message)) {
    console.warn(`Already downloaded: ${plan.finalPath}`);
    return plan.finalPath; // treat as success/idempotent
  }
  throw err;
}

Prevention

When it happens

Trigger: plan.finalPath already exists in the output root when commitIllustPlan finishes staging, i.e. a previous run of bookmark-download already saved this artwork at that path.

Common situations: Running bookmark-download twice with the same --output directory; two parallel download processes racing to save the same bookmark; a leftover partial download from a crashed earlier run; an unrelated file coincidentally named like the artwork in the output folder.

Related errors


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