{"record":{"id":"c825ffb562e5965d","repo":"yamadashy/repomix","slug":"skill-output-path-exists-but-is-not-a-directory","errorCode":null,"errorMessage":"Skill output path exists but is not a directory: ${skillDir}","messagePattern":"Skill output path exists but is not a directory: (.+?)","errorType":"exception","errorClass":"RepomixError","httpStatus":null,"severity":"error","filePath":"src/cli/prompts/skillPrompts.ts","lineNumber":124,"sourceCode":"/**\n * Prepare skill directory for non-interactive mode.\n * Handles force overwrite by removing existing directory.\n */\nexport const prepareSkillDir = async (\n  skillDir: string,\n  force: boolean,\n  deps = {\n    access: fs.access,\n    rm: fs.rm,\n    stat: fs.stat,\n  },\n): Promise<void> => {\n  try {\n    await deps.access(skillDir);\n    // Path exists - check if it's a directory\n    const stats = await deps.stat(skillDir);\n    if (!stats.isDirectory()) {\n      throw new RepomixError(`Skill output path exists but is not a directory: ${skillDir}`);\n    }\n    // Directory exists\n    if (force) {\n      await deps.rm(skillDir, { recursive: true, force: true });\n    } else {\n      throw new RepomixError(`Skill directory already exists: ${skillDir}. Use --force to overwrite.`);\n    }\n  } catch (error) {\n    // Re-throw if it's not a \"file not found\" error\n    if ((error as NodeJS.ErrnoException)?.code !== 'ENOENT') {\n      throw error;\n    }\n    // Directory doesn't exist - good to go\n  }\n};\n\n/**\n * Resolve skill output path and prepare directory for non-interactive mode.","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/yamadashy/repomix/blob/f465ad909315a22120636baf03fa5e28701a50cb/src/cli/prompts/skillPrompts.ts#L106-L142","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the path: `ls -la <skillDir>` / `file <skillDir>` to see what occupies it.","Remove or rename the offending file: `rm <skillDir>` (or mv it aside), then re-run the command.","Fix your output argument to point at a fresh directory path that does not collide with an existing file.","If the entry is a stale artifact of a prior run, deleting it is safe; the command will then create the directory."],"exampleFix":"# before\nrepomix --skill --output my-skill   # my-skill is a regular file\n\n# after\nrm my-skill            # or: mv my-skill my-skill.bak\nrepomix --skill --output my-skill","handlingStrategy":"validation","validationCode":"import fs from 'node:fs/promises';\ntry {\n  const st = await fs.stat(skillDir);\n  if (!st.isDirectory()) {\n    console.error(`${skillDir} exists and is not a directory; remove or rename it first.`);\n    process.exit(1);\n  }\n} catch { /* does not exist: fine */ }","typeGuard":null,"tryCatchPattern":"try {\n  await resolveAndPrepareSkillDir(skillOutput, cwd, force);\n} catch (e) {\n  if (e instanceof RepomixError && e.message.includes('exists but is not a directory')) {\n    console.error('Target path is a file; delete/rename it or pick another output path.');\n  } else throw e;\n}","preventionTips":["Check the output path with `ls -la` before running non-interactively.","Don't pass output paths that collide with existing files.","Use distinct names per skill generation to avoid collisions.","Watch for stale files left by previous failed runs at the same path."],"tags":["filesystem","skill-generation","path-conflict","cli"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"f465ad909315a22120636baf03fa5e28701a50cb","analyzedAt":"2026-08-29T01:27:42.024Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}