paperclipai/paperclip · error · Error
ACPX runtime directory must be a directory
Error message
ACPX runtime directory must be a directory
What it means
resolveAcpxRuntimeRoot resolves and validates the base runtime directory used to build per-session ACPX runtime paths. After resolving symlinks with realpath and stat-ing the path, it requires the target to actually be a directory. This error is thrown when the configured runtimeDirectory path exists but is a file, socket, or other non-directory entry.
Source
Thrown at packages/paperclip-runner/src/drivers/acpx/recovery-identity.ts:307
if (!value.trim()) throw new Error("ACPX working directory is required");
const workspacePath = await realpath(value);
const metadata = await stat(workspacePath);
if (!metadata.isDirectory() || workspacePath === dirname(workspacePath)) {
throw new Error("ACPX working directory must be a non-root directory");
}
return workspacePath;
}
export async function resolveAcpxRuntimeRoot(
runtimeDirectory: string,
sessionId: string,
): Promise<string> {
if (!runtimeDirectory.trim())
throw new Error("ACPX runtime directory is required");
const root = await realpath(runtimeDirectory);
const metadata = await stat(root);
if (!metadata.isDirectory())
throw new Error("ACPX runtime directory must be a directory");
if (root === dirname(root))
throw new Error("ACPX runtime directory must not be a filesystem root");
return join(
resolve(root),
"acpx",
acpxRuntimeSessionDirectoryName(sessionId),
);
}
/**
* Return the stable, filesystem-safe directory name used for one normalized
* ACPX session below the runtime's `acpx` namespace.
*/
export function acpxRuntimeSessionDirectoryName(sessionId: string): string {
const readable = sessionId
.replace(/[^a-zA-Z0-9._-]/g, "_")
.replace(/^\.+$/, "session")
.slice(0, 80);View on GitHub (pinned to 01ad858492)
Solutions
- Check what the path actually is (ls -la / stat) and point the config at a real directory.
- Create the directory if it is missing, or remove the file occupying the path and mkdir the intended runtime directory.
- Fix symlink targets so they reference directories.
- Validate the path is a directory in your config loader before constructing the driver.
Example fix
// before
const driver = createAcpxDriver({ runtimeDirectory: "/var/lib/paperclip/runtime.json" }); // a file
// after
await mkdir("/var/lib/paperclip/runtime", { recursive: true });
const driver = createAcpxDriver({ runtimeDirectory: "/var/lib/paperclip/runtime" }); Defensive patterns
Strategy: validation
Validate before calling
import { statSync } from "node:fs";
if (!statSync(runtimeDirectory).isDirectory()) {
throw new Error(`ACPX runtime path must be a directory: ${runtimeDirectory}`);
} Prevention
- Point runtimeDirectory at a dedicated directory, never a file or socket.
- Create the directory with mkdir -p during provisioning.
- Audit symlinks in the runtime path when migrating environments.
When it happens
Trigger: Calling runtimeRoot()/resolveAcpxRuntimeRoot with a runtimeDirectory that realpath+stat resolves to a non-directory — e.g. the config points at a regular file, a symlink to a file, or a Unix socket path.
Common situations: Config value accidentally set to a file (e.g. a config file inside the runtime dir); a symlink that was repointed to a file; leftover artifact where a directory was replaced by a file during a failed cleanup or migration.
Related errors
- ACPX runtime directory must not be a filesystem root
- Registered ${label} Paperclip config is missing its adjacent
- Registered base project workspace Paperclip config at ${conf
- ${label} does not exist at ${resolved}.
- ${label} is not a regular file at ${canonical}.
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/988c6e02e4485ad4.
Report an issue: GitHub.