{"record":{"id":"027108fcde87c4d6","repo":"ruvnet/ruflo","slug":"path-is-not-a-directory-resolvedpath","errorCode":null,"errorMessage":"Path is not a directory: ${resolvedPath}","messagePattern":"Path is not a directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/cli.ts","lineNumber":42,"sourceCode":"  const errorMessage = error instanceof Error ? error.message : String(error);\n  console.error(chalk.red.bold('\\nError:'), chalk.red(message ?? errorMessage));\n\n  if (error instanceof Error && error.stack && process.env.DEBUG) {\n    console.error(chalk.gray('\\nStack trace:'));\n    console.error(chalk.gray(error.stack));\n  }\n\n  process.exit(1);\n}\n\n// Validate project path exists and is accessible\nasync function validatePath(projectPath: string): Promise<string> {\n  const resolvedPath = path.resolve(projectPath);\n\n  try {\n    const stats = await fs.stat(resolvedPath);\n    if (!stats.isDirectory()) {\n      throw new Error(`Path is not a directory: ${resolvedPath}`);\n    }\n    return resolvedPath;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n      // Directory doesn't exist, try to create it\n      console.log(chalk.yellow(`Creating directory: ${resolvedPath}`));\n      await fs.ensureDir(resolvedPath);\n      return resolvedPath;\n    }\n    throw error;\n  }\n}\n\n// Validate skill name format\nfunction validateSkillName(name: string): boolean {\n  const validPattern = /^[a-z][a-z0-9-]*$/;\n  return validPattern.test(name);\n}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/cli.ts#L24-L60","documentation":"validatePath() in the @claude-flow/codex CLI resolves the project-path argument and stats it. If the path exists but is not a directory (a regular file, symlink to a file, etc.) it throws this error. ENOENT is special-cased: a missing directory is created with fs.ensureDir and returned, so this message specifically means 'something exists at that path but it is not a folder'. Other stat failures (e.g. EACCES) rethrow as the raw OS error.","triggerScenarios":"(1) Passing a file as --path, e.g. `--path ./package.json` or `--path ./config/default.toml`; (2) a shell variable that was expanded from a file glob (`--path src/*.ts` matching one file); (3) a symlink at the target path pointing to a file; (4) a socket/device node occupying the path.","commonSituations":"CLI flags documented as 'project directory' being given a config file path by wrapper scripts; copy-pasted commands where the path was a file in the original tutorial; misconfigured CI variables holding an artifact path.","solutions":["Point --path at the project root directory, not any file inside it.","If you expected the directory to be auto-created, first remove the file occupying that exact path — auto-creation only triggers when the path does not exist (ENOENT).","Verify with `ls -ld <path>` (or `test -d <path>`) before running the CLI.","If the path lives under a file (e.g. file.txt/subdir), fix the parent structure — that surfaces as a different raw error but stems from the same mistake."],"exampleFix":"# before\n$ npx @claude-flow/codex init --path ./package.json\nError: Path is not a directory: /repo/package.json\n\n# after\n$ npx @claude-flow/codex init --path .\n# (or point at an absent path to have it created automatically)","handlingStrategy":"validation","validationCode":"import { stat } from 'node:fs/promises';\nasync function assertProjectDir(p: string): Promise<string> {\n  try {\n    const s = await stat(p);\n    if (!s.isDirectory()) throw new Error(`refusing to use ${p}: it is a file, not a directory`);\n    return p;\n  } catch (e) {\n    if ((e as NodeJS.ErrnoException).code === 'ENOENT') return p; // CLI will create it\n    throw e; // EACCES etc.\n  }\n}\n// wrap the CLI call:\nawait execFile('npx', ['@claude-flow/codex', 'init', '--path', await assertProjectDir(dir)]);","typeGuard":null,"tryCatchPattern":"try {\n  await runCodexCli(['--path', target]);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Path is not a directory:')) {\n    // message carries the resolved absolute path — inspect it\n    throw new Error(`--path must be a directory; got a file: ${err.message}`);\n  }\n  throw err;\n}","preventionTips":["Validate `test -d \"$PATH\"` in wrapper scripts before invoking the CLI","Remember the CLI auto-creates missing directories (ENOENT) but refuses existing files — clear the file if the path should be a new dir","Beware glob expansion in CI variables: an unquoted $TARGET matching one file lands here","Check symlinks with ls -ld — a link to a file is still not a directory"],"tags":["cli","path-validation","filesystem","codex"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}