paperclipai/paperclip · error
Codex working directory must exist before provider admission
Error message
Codex working directory must exist before provider admission
What it means
The boundary validator resolves the requested working directory and calls `statSync` to confirm it exists and is a directory. When the stat fails with ENOENT, the path does not exist on disk, and admission is refused because the Codex session requires a real directory to run in. Note the catch also rethrows other stat errors unchanged.
Source
Thrown at packages/paperclip-runner/src/drivers/codex/codex-boundaries.ts:62
authority: CodexWorkingDirectoryAuthority = "local_filesystem",
): string {
if (workingDirectory.trim().length === 0) {
throw new Error("Codex working directory is required");
}
if (authority === "remote_runner") {
return validateRemoteRunnerWorkingDirectory(workingDirectory, environment);
}
const requested = resolve(workingDirectory);
let resolved: string;
try {
resolved = realpathSync.native(requested);
if (!statSync(resolved).isDirectory()) {
throw new Error("Codex working directory must be a directory");
}
} catch (error) {
const code = (error as NodeJS.ErrnoException).code;
if (code === "ENOENT") {
throw new Error(
"Codex working directory must exist before provider admission",
);
}
throw error;
}
if (resolved === parse(resolved).root) {
throw new Error("Codex working directory cannot be a filesystem root");
}
const configuredRoot = environment.PAPERCLIP_WORKSPACE_CWD;
const hostHome = canonicalConfiguredPath(environment.HOME);
if (hostHome && pathContains(resolved, hostHome)) {
throw new Error("Codex working directory cannot contain the host HOME");
}
if (
hostHome &&
SENSITIVE_HOST_HOME_DIRECTORIES.some((directory) =>
pathContains(resolve(hostHome, directory), resolved),
)View on GitHub (pinned to 01ad858492)
Solutions
- Create the working directory before starting the run (fs.mkdir recursive)
- Verify the configured path exists on the machine running the driver
- Check provisioning/cleanup jobs that may delete workspaces prematurely
- If it is a dangling symlink, remove it and create the real directory
Example fix
// before
validateCodexWorkingDirectory("/workspaces/agent-42");
// after
mkdirSync("/workspaces/agent-42", { recursive: true });
validateCodexWorkingDirectory("/workspaces/agent-42"); Defensive patterns
Strategy: validation
Validate before calling
import { statSync } from "node:fs";
try {
if (!statSync(cwd).isDirectory()) throw new Error("not a directory");
} catch {
mkdirSync(cwd, { recursive: true });
} Type guard
function directoryExists(p: string): boolean {
try { return statSync(p).isDirectory(); } catch { return false; }
} Try / catch
try {
validateCodexWorkingDirectory(cwd);
} catch (err) {
if (err.message.includes("must exist before provider admission")) {
mkdirSync(cwd, { recursive: true });
validateCodexWorkingDirectory(cwd); // retry once after provisioning
} else throw err;
} Prevention
- Provision the workspace directory before enqueuing the run
- Audit cleanup jobs so they don't delete workspaces of scheduled tasks
- Verify path mounts exist inside containers at startup
When it happens
Trigger: Calling `validateCodexWorkingDirectory` with a path whose parent exists but target directory was deleted, never created, or is on an unmounted volume (ENOENT).
Common situations: Workspace directory removed by cleanup between scheduling and run start; typo in configured path; running in a fresh container where workspace provisioning step was skipped; symlink pointing to a deleted target.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- codex auth cache: account_id is not a valid account handle
- ${label} is not a regular file at ${canonical}.
- workspace_durable_seed_invalid
- device-login promotion: the account identifier cannot form a
- codex auth cache: account-home directory no longer exists; r
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/1721342ca853731a.
Report an issue: GitHub.