yamadashy/repomix · error · RepomixError

Skill output path exists but is not a directory: ${skillDir}

Error message

Skill output path exists but is not a directory: ${skillDir}

What it means

In non-interactive skill generation, prepareSkillDir checks the target skill directory with access() then stat(). If the path exists but stat reports it is not a directory (a regular file, symlink to a file, FIFO, etc.), Repomix throws this RepomixError rather than deleting or clobbering a non-directory path. resolveAndPrepareSkillDir calls this with the resolved skill output path before writing the skill.

Source

Thrown at src/cli/prompts/skillPrompts.ts:124

/**
 * Prepare skill directory for non-interactive mode.
 * Handles force overwrite by removing existing directory.
 */
export const prepareSkillDir = async (
  skillDir: string,
  force: boolean,
  deps = {
    access: fs.access,
    rm: fs.rm,
    stat: fs.stat,
  },
): Promise<void> => {
  try {
    await deps.access(skillDir);
    // Path exists - check if it's a directory
    const stats = await deps.stat(skillDir);
    if (!stats.isDirectory()) {
      throw new RepomixError(`Skill output path exists but is not a directory: ${skillDir}`);
    }
    // Directory exists
    if (force) {
      await deps.rm(skillDir, { recursive: true, force: true });
    } else {
      throw new RepomixError(`Skill directory already exists: ${skillDir}. Use --force to overwrite.`);
    }
  } catch (error) {
    // Re-throw if it's not a "file not found" error
    if ((error as NodeJS.ErrnoException)?.code !== 'ENOENT') {
      throw error;
    }
    // Directory doesn't exist - good to go
  }
};

/**
 * Resolve skill output path and prepare directory for non-interactive mode.

View on GitHub (pinned to f465ad9093)

Solutions

  1. Inspect the path: `ls -la <skillDir>` / `file <skillDir>` to see what occupies it.
  2. Remove or rename the offending file: `rm <skillDir>` (or mv it aside), then re-run the command.
  3. Fix your output argument to point at a fresh directory path that does not collide with an existing file.
  4. If the entry is a stale artifact of a prior run, deleting it is safe; the command will then create the directory.

Example fix

# before
repomix --skill --output my-skill   # my-skill is a regular file

# after
rm my-skill            # or: mv my-skill my-skill.bak
repomix --skill --output my-skill
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs/promises';
try {
  const st = await fs.stat(skillDir);
  if (!st.isDirectory()) {
    console.error(`${skillDir} exists and is not a directory; remove or rename it first.`);
    process.exit(1);
  }
} catch { /* does not exist: fine */ }

Try / catch

try {
  await resolveAndPrepareSkillDir(skillOutput, cwd, force);
} catch (e) {
  if (e instanceof RepomixError && e.message.includes('exists but is not a directory')) {
    console.error('Target path is a file; delete/rename it or pick another output path.');
  } else throw e;
}

Prevention

When it happens

Trigger: Running skill generation non-interactively (with an explicit output path) where skillDir already exists as a non-directory — commonly a plain file was created earlier at the same path, or a symlink to a file occupies the path.

Common situations: A previous failed run left a file named like the skill directory; the user's output value collides with an existing file (e.g. `--output my-skill` where my-skill is a file); editors/tools created a lockfile or notes file at that name.

Related errors


AI-assisted analysis of yamadashy/repomix@f465ad9093 (2026-08-29). Data as JSON: /api/errors/c825ffb562e5965d. Report an issue: GitHub.