JuliusBrussee/caveman · error · Error
failed to read CODEX_HOME
Error message
failed to read CODEX_HOME ${JSON.stringify(configured)}: ${(error as Error).message} What it means
Thrown when resolving CODEX_HOME fails with a filesystem error other than ENOENT (e.g. EACCES, ENOTDIR). The CLI stats the configured CODEX_HOME path before use and wraps any non-missing-file read failure into this error, including the OS error message. It means the path exists conceptually but could not be stat'ed.
Solutions
- Verify the CODEX_HOME path: run `ls -la` on it and each ancestor to find the inaccessible or wrong component
- Fix the path in the environment (unset CODEX_HOME or point it at an existing writable directory)
- Correct permissions on ancestor directories (chmod +x on directories along the path)
- Re-run the command; if it is a transient mount/I/O problem, retry after the filesystem is healthy
Example fix
// before CODEX_HOME=/home/user/notes.txt codex ... // after CODEX_HOME=/home/user/.codex codex ...
Defensive patterns
Strategy: try-catch
Validate before calling
const configured = process.env.CODEX_HOME;
if (configured) {
try { const st = fs.statSync(configured); if (!st.isDirectory()) throw new Error(`${configured} is not a directory`); }
catch (e) { console.error(`Cannot access CODEX_HOME ${configured}: ${e.message}`); }
} Type guard
function isAccessibleDir(p: string): boolean {
try { return fs.statSync(p).isDirectory(); } catch { return false; }
} Try / catch
try {
runCodexCommand();
} catch (e) {
if (String(e.message).startsWith("failed to read CODEX_HOME")) {
console.error(`CODEX_HOME is set but unreadable: ${e.message}. Fix the path or unset CODEX_HOME.`);
}
} Prevention
- Verify CODEX_HOME exists and is a directory before launching the CLI
- Never point CODEX_HOME inside or at a file path
- Keep execute permission on all ancestor directories
- Quote env values to avoid stray characters in the path
When it happens
Trigger: statSync(configured) on the CODEX_HOME path throws an ErrnoException whose code is not ENOENT — e.g. a parent directory component is not a directory (ENOTDIR), permission is denied (EACCES), or an I/O error occurs on the path.
Common situations: CODEX_HOME pointing inside a file path (e.g. /home/user/file.txt/subdir), a symlink with no search permission on an ancestor directory, a network mount being unavailable, or running as a user lacking execute permission on a parent directory.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- CODEX_HOME points to
- failed to canonicalize CODEX_HOME
- CAVEMAN_AUTH_TOKEN must be at least
- CAVEMAN_CCR_MAX_BYTES must be a positive integer
- CODEX_HOME points to
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/7fec6bb154cb7bc1.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:6200
if (!prefix || !path.startsWith(prefix)) return path;
const root = agent === "claude" ? claudeConfigDir() : codexHomeDir();
return join(root, path.slice(prefix.length));
}
export function codexHomeDir(env: NodeJS.ProcessEnv = process.env): string {
const configured = env.CODEX_HOME;
if (!configured) return join(homedir(), ".codex");
// Match Codex's own home resolver: a nonempty override may be relative, but
// must already be a directory and is canonicalized before use. Never fall
// back to another account's default home when the override is invalid.
let metadata: ReturnType<typeof statSync>;
try {
metadata = statSync(configured);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
throw new Error(`CODEX_HOME points to ${JSON.stringify(configured)}, but that path does not exist`);
}
throw new Error(`failed to read CODEX_HOME ${JSON.stringify(configured)}: ${(error as Error).message}`);
}
if (!metadata.isDirectory()) {
throw new Error(`CODEX_HOME points to ${JSON.stringify(configured)}, but that path is not a directory`);
}
try {
return realpathSync(configured);
} catch (error) {
throw new Error(`failed to canonicalize CODEX_HOME ${JSON.stringify(configured)}: ${(error as Error).message}`);
}
}
function codexAuthPath(): string {
return join(codexHomeDir(), "auth.json");
}
function nonEmptyString(v: unknown): v is string {
return typeof v === "string" && v.trim().length > 0;
}View on GitHub (pinned to 3ee70a1026)