jackwener/OpenCLI · error · CommandExecutionError

Failed to inspect Pixiv download target ${target}: ${error?.

Error message

Failed to inspect Pixiv download target ${target}: ${error?.message || error}

What it means

pixivPathEntryExists uses fs.lstatSync to test whether a download destination exists. ENOENT is treated as 'does not exist', but any other lstat failure (EACCES, ELOOP, ENOTDIR, EIO, etc.) is unrecoverable for the safety check, so a CommandExecutionError wrapping the underlying message is thrown.

Source

Thrown at clis/pixiv/novel-download-utils.js:106

  let canonicalAncestor;
  try {
    canonicalAncestor = fs.realpathSync.native(ancestor);
  } catch {
    throw new ArgumentError(`output path is not a safe directory: ${ancestor}`);
  }
  if (!fs.statSync(canonicalAncestor).isDirectory()) {
    throw new ArgumentError(`output path is not a safe directory: ${ancestor}`);
  }
  return path.join(canonicalAncestor, ...missingParts);
}

export function pixivPathEntryExists(target) {
  try {
    fs.lstatSync(target);
    return true;
  } catch (error) {
    if (error?.code === 'ENOENT') return false;
    throw new CommandExecutionError(`Failed to inspect Pixiv download target ${target}: ${error?.message || error}`);
  }
}

export async function fetchNovelForDownload(page, id) {
  const body = await pixivFetch(page, `/ajax/novel/${id}`, {
    notFoundMsg: `Novel not found: ${id}`,
  });
  return requireNovelDownloadBody(body, id);
}

export function formatNovelContent(body, format) {
  const tags = tagsToString(body.tags);
  const url = `https://www.pixiv.net/novel/show.php?id=${body.id}`;
  if (format === 'md') {
    return [
      `# ${body.title}`,
      '',
      `- Author: ${body.userName}`,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Fix permissions on the destination's parent directories (chmod/chown for the running user).
  2. Remove symlink loops or dead links in the path (find -type l -xtype l).
  3. Ensure every component of the output path except the final entry is a directory.
  4. Reconnect/remount the storage volume and retry; if transient, wrap the call in retry with backoff.

Example fix

// before
-o /mnt/usb/novels   // usb unmounted -> EIO on lstat
// after (shell)
$ mount /mnt/usb && pixiv-novel download 12345 -o /mnt/usb/novels
Defensive patterns

Strategy: retry

Validate before calling

import fs from 'node:fs';
function canProbe(p) {
  try { fs.lstatSync(p); return true; }
  catch (e) { return e.code === 'ENOENT'; }
}

Try / catch

try {
  await downloadNovel(id, { output });
} catch (e) {
  if (e.message.startsWith('Failed to inspect Pixiv download target')) {
    console.error(`Fix filesystem access for output path: ${e.message}`);
    // remount/chmod, then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: prepareIllustPlan, commitIllustPlan, or prepareNovelFile probes a destination path whose parent directory denies permission, contains a symlink loop, has a non-directory component, or the path is on a failing volume.

Common situations: Output directory made read-only or owned by another user; destination path contains a dead symlink; output path passes through a file (ENOTDIR); disk/USB/network drive dropped offline mid-session.

Related errors


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