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

  1. Pass "workspace" verbatim to enable filesystem sandboxing, or pass null/undefined/"" to leave it unset.
  2. If your config layer exposes a richer enum, translate it to the adapter's vocabulary at the boundary: "rw" | "ro" -> "workspace".
  3. 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.
  4. 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

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


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/599ba0695515d119. Report an issue: GitHub.