paperclipai/paperclip · error
filesystemScope must be "workspace".
Error message
filesystemScope must be "workspace".
What it means
Thrown by parseLocalProcessFilesystemScope when the supplied value is non-empty but not exactly "workspace". The filesystem sandbox currently implements exactly one mode: bind-mounting a workspace directory read-write inside a bubblewrap container and isolating everything else. Other scopes (e.g. read-only, host, custom) are not implemented, so any other literal is rejected rather than silently ignored.
Source
Thrown at packages/adapter-utils/src/local-process-sandbox.ts:160
export function parseLocalProcessNetworkAllowlist(value: unknown): string[] {
if (!Array.isArray(value)) return [];
return value.map((entry, index) => {
if (typeof entry !== "string") throw new Error(`networkAllowlist[${index}] must be a string.`);
const rule = parseNetworkAllowlistEntry(entry, index);
return rule.port ? `${rule.hostname}:${rule.port}` : rule.hostname;
});
}
export function parseLocalProcessNetworkScope(value: unknown): LocalProcessNetworkScope | null {
if (value == null || value === "") return null;
if (value === "deny" || value === "allowlist") return value;
throw new Error('networkScope must be "deny" or "allowlist".');
}
export function parseLocalProcessFilesystemScope(value: unknown): "workspace" | null {
if (value == null || value === "") return null;
if (value === "workspace") return value;
throw new Error('filesystemScope must be "workspace".');
}
function isNetworkTargetAllowed(hostname: string, port: string, rules: NetworkAllowlistRule[]): boolean {
const normalizedHostname = hostname.toLowerCase().replace(/^\[|\]$/g, "");
return rules.some((rule) => rule.hostname === normalizedHostname && (rule.port === null || rule.port === port));
}
function assertUnixSocketPathLength(socketPath: string): void {
const pathBytes = Buffer.byteLength(socketPath);
if (pathBytes > UNIX_SOCKET_PATH_MAX_BYTES) {
throw new Error(
`Paperclip sandbox proxy socket path is ${pathBytes} bytes, exceeding the Linux limit of ${UNIX_SOCKET_PATH_MAX_BYTES}: ${socketPath}`,
);
}
}
async function createNetworkProxyTempDir(): Promise<string> {
const candidates = Array.from(new Set(["/tmp", os.tmpdir()]));View on GitHub (pinned to 67001ec6eb)
Solutions
- Pass "workspace" verbatim to enable filesystem sandboxing, or pass null/undefined/"" to leave it unset.
- If your config layer exposes a richer enum, translate it to the adapter's vocabulary at the boundary: "rw" | "ro" -> "workspace".
- If you genuinely need a non-workspace filesystem scope, that mode is not yet supported — file an issue and run without filesystemScope (rely on networkScope alone) until it lands.
- Document the accepted literal next to the option in your config schema so callers do not guess.
Example fix
// before
const fs = parseLocalProcessFilesystemScope("read-write");
// after
const fs = parseLocalProcessFilesystemScope("workspace"); Defensive patterns
Strategy: validation
Validate before calling
function normalizeFilesystemScope(value: unknown): "workspace" | null {
if (value == null || value === "") return null;
const legacy = { rw: "workspace", ro: "workspace", readwrite: "workspace" } as Record<string, string>;
const mapped = typeof value === "string" ? (legacy[value] ?? value) : value;
if (mapped !== "workspace") {
throw new Error(`Unsupported filesystemScope: ${String(value)} (only "workspace" is implemented)`);
}
return "workspace";
} Type guard
function isFilesystemScope(value: unknown): value is "workspace" {
return value === "workspace";
} Try / catch
try {
const scope = parseLocalProcessFilesystemScope(config.filesystemScope);
} catch (error) {
if (error instanceof Error && error.message.startsWith('filesystemScope must be')) {
throw new ConfigError(`filesystemScope only supports \"workspace\" (got: ${String(config.filesystemScope)})`, { cause: error });
}
throw error;
} Prevention
- Expose only the implemented scope in your config schema's enum.
- Map legacy "rw"/"ro" values to "workspace" at the config boundary.
- Document the accepted literal next to the option to prevent guessing.
When it happens
Trigger: Calling parseLocalProcessFilesystemScope with values like "read-only", "rw", "host", "full", "true", true, or "sandbox". The function only accepts null/"" (-> null, scope unset) or the literal string "workspace"; everything else hits the throw at local-process-sandbox.ts:160.
Common situations: Config schemas that ship a generic enum without reading the adapter's accepted values, an older API that allowed "rw"/"ro", or a UI that submits the boolean true to enable filesystem isolation. Migration from another sandbox tool's vocabulary (firejail, nsjail) also produces mismatches.
Related errors
- Sandbox cwd "${cwd}" must be inside workspaceDir "${workspac
- Writable sandbox path "${normalizedExtraPath}" is outside sy
- Sandbox path alias "${aliasPath}" must target the synchroniz
- filesystemExtraPaths[${index}] must be an absolute path or {
- filesystemExtraPaths[${index}] must use access "ro" or "rw"
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/599ba0695515d119.
Report an issue: GitHub.