paperclipai/paperclip · error
Local process sandbox requires a filesystem or network scope
Error message
Local process sandbox requires a filesystem or network scope.
What it means
Thrown by buildLocalProcessSandboxSpawnTarget when both filesystemScope and networkScope resolve to null. The sandbox exists to restrict at least one axis (filesystem or network); if neither is configured there is nothing for bubblewrap to do, so the function refuses to construct an empty sandbox that would give a false sense of isolation.
Source
Thrown at packages/adapter-utils/src/local-process-sandbox.ts:352
else process.exit(code == null ? 1 : code);
}));
});
`;
return source.trimStart();
}
export async function buildLocalProcessSandboxSpawnTarget(input: {
executable: string;
args: string[];
cwd: string;
options: LocalProcessSandboxOptions;
}): Promise<LocalProcessSandboxSpawnTarget> {
if (process.platform !== "linux") {
throw new Error("Local process filesystem and network scopes are currently supported only on Linux.");
}
const filesystemScope = input.options.filesystemScope ?? null;
const networkScope = input.options.networkScope ?? null;
if (!filesystemScope && !networkScope) throw new Error("Local process sandbox requires a filesystem or network scope.");
const workspaceDir = normalizeAbsolutePath(input.options.workspaceDir, "Sandbox workspaceDir");
const cwd = normalizeAbsolutePath(input.cwd, "Sandbox cwd");
if (filesystemScope === "workspace") {
const relativeCwd = path.relative(workspaceDir, cwd);
if (relativeCwd.startsWith("..") || path.isAbsolute(relativeCwd)) {
throw new Error(`Sandbox cwd "${cwd}" must be inside workspaceDir "${workspaceDir}".`);
}
const outboundRestorePaths = (input.options.outboundRestorePaths ?? []).map((candidate, index) =>
normalizeAbsolutePath(candidate, `Sandbox outboundRestorePaths[${index}]`));
for (const [index, extraPath] of (input.options.extraPaths ?? []).entries()) {
if (extraPath.access !== "rw") continue;
const normalizedExtraPath = normalizeAbsolutePath(extraPath.path, `Sandbox extraPaths[${index}].path`);
const relativeToWorkspace = path.relative(workspaceDir, normalizedExtraPath);
const synchronized = !relativeToWorkspace.startsWith("..") && !path.isAbsolute(relativeToWorkspace);
const restored = outboundRestorePaths.some((restorePath) => {
const relative = path.relative(restorePath, normalizedExtraPath);
return !relative.startsWith("..") && !path.isAbsolute(relative);View on GitHub (pinned to 67001ec6eb)
Solutions
- Set at least one scope: filesystemScope: "workspace" and/or networkScope: "deny" or "allowlist".
- If you genuinely want no sandboxing, skip buildLocalProcessSandboxSpawnTarget entirely and spawn the executable directly — do not call it with both scopes unset.
- Add a config assertion upstream: if (filesystemScope == null && networkScope == null) throw new Error("configure at least one sandbox scope"); to surface the issue earlier with your own message.
- Audit the default option object in your adapter to ensure it always sets one scope when sandboxing is enabled.
Example fix
// before
buildLocalProcessSandboxSpawnTarget({
...input,
options: { ...input.options, filesystemScope: null, networkScope: null },
});
// after
buildLocalProcessSandboxSpawnTarget({
...input,
options: { ...input.options, filesystemScope: "workspace", networkScope: "deny" },
}); Defensive patterns
Strategy: validation
Validate before calling
function assertSandboxScope(opts: { filesystemScope: string | null; networkScope: string | null }): void {
if (!opts.filesystemScope && !opts.networkScope) {
throw new Error("At least one sandbox scope (filesystemScope or networkScope) must be set; otherwise skip the sandbox builder.");
}
}
assertSandboxScope({ filesystemScope, networkScope });
const target = await buildLocalProcessSandboxSpawnTarget(input); Type guard
function hasAnySandboxScope(opts: { filesystemScope: string | null; networkScope: string | null }): boolean {
return Boolean(opts.filesystemScope) || Boolean(opts.networkScope);
} Try / catch
try {
return await buildLocalProcessSandboxSpawnTarget(input);
} catch (error) {
if (error instanceof Error && error.message.includes("requires a filesystem or network scope")) {
return { command: input.executable, args: input.args, cwd: input.cwd, env: process.env, cleanup: undefined };
}
throw error;
} Prevention
- Decide upstream whether sandboxing is on or off; do not route through the sandbox builder with both scopes empty.
- Add a config assertion that rejects both-scopes-null when sandboxing is enabled.
- Make your adapter's default option object always set one scope in sandbox mode.
When it happens
Trigger: Calling buildLocalProcessSandboxSpawnTarget with options where both filesystemScope and networkScope are null, undefined, or empty string. The check at local-process-sandbox.ts:352 runs after the platform guard, so this is the second precondition before any path validation.
Common situations: Config layer defaults both options to null but still routes through buildLocalProcessSandboxSpawnTarget instead of the unsandboxed spawn path; a UI that lets the user clear both scope selectors but still calls the sandbox builder; or a feature flag that was supposed to enable one scope but is disabled, leaving both empty.
Related errors
- networkAllowlist[${index}] must be a string.
- networkScope must be "deny" or "allowlist".
- filesystemScope must be "workspace".
- networkScope="allowlist" requires at least one valid network
- Sandbox cwd "${cwd}" must be inside workspaceDir "${workspac
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/2be01e11a377fcec.
Report an issue: GitHub.