ruvnet/ruflo · error
Path is not a directory: ${resolvedPath}
Error message
Path is not a directory: ${resolvedPath} What it means
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.
Source
Thrown at v3/@claude-flow/codex/src/cli.ts:42
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(chalk.red.bold('\nError:'), chalk.red(message ?? errorMessage));
if (error instanceof Error && error.stack && process.env.DEBUG) {
console.error(chalk.gray('\nStack trace:'));
console.error(chalk.gray(error.stack));
}
process.exit(1);
}
// Validate project path exists and is accessible
async function validatePath(projectPath: string): Promise<string> {
const resolvedPath = path.resolve(projectPath);
try {
const stats = await fs.stat(resolvedPath);
if (!stats.isDirectory()) {
throw new Error(`Path is not a directory: ${resolvedPath}`);
}
return resolvedPath;
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
// Directory doesn't exist, try to create it
console.log(chalk.yellow(`Creating directory: ${resolvedPath}`));
await fs.ensureDir(resolvedPath);
return resolvedPath;
}
throw error;
}
}
// Validate skill name format
function validateSkillName(name: string): boolean {
const validPattern = /^[a-z][a-z0-9-]*$/;
return validPattern.test(name);
}View on GitHub (pinned to fa13ee4ad6)
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.
Example fix
# before $ npx @claude-flow/codex init --path ./package.json Error: Path is not a directory: /repo/package.json # after $ npx @claude-flow/codex init --path . # (or point at an absent path to have it created automatically)
Defensive patterns
Strategy: validation
Validate before calling
import { stat } from 'node:fs/promises';
async function assertProjectDir(p: string): Promise<string> {
try {
const s = await stat(p);
if (!s.isDirectory()) throw new Error(`refusing to use ${p}: it is a file, not a directory`);
return p;
} catch (e) {
if ((e as NodeJS.ErrnoException).code === 'ENOENT') return p; // CLI will create it
throw e; // EACCES etc.
}
}
// wrap the CLI call:
await execFile('npx', ['@claude-flow/codex', 'init', '--path', await assertProjectDir(dir)]); Try / catch
try {
await runCodexCli(['--path', target]);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Path is not a directory:')) {
// message carries the resolved absolute path — inspect it
throw new Error(`--path must be a directory; got a file: ${err.message}`);
}
throw err;
} Prevention
- 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
When it happens
Trigger: (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.
Common situations: 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.
Related errors
- ${label} contains shell metacharacters
- Event log path contains null bytes
- unknown game "${key}". Known: ${Object.keys(GAMES).join(', '
- hexToBytes: odd-length hex string
- trajectory envelope not found: ${path}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/027108fcde87c4d6.
Report an issue: GitHub.