paperclipai/paperclip · error

Assigned remote workspace must be a normalized absolute path

Error message

Assigned remote workspace must be a normalized absolute path

What it means

The assigned workspace itself (the trimmed PAPERCLIP_WORKSPACE_CWD value) is validated before use: it must be a POSIX absolute path already in normalized form (posix.isAbsolute and posix.normalize(value) === value). This throws when the configured workspace root is relative, contains redundant segments like "//", ".", or "..", has a trailing slash, or otherwise differs from its normalized form.

Source

Thrown at packages/paperclip-runner/src/drivers/codex/codex-boundaries.ts:146

  ) {
    throw new Error(
      "Remote Codex working directory must be a normalized absolute path",
    );
  }
  if (workingDirectory === posix.parse(workingDirectory).root) {
    throw new Error("Codex working directory cannot be a filesystem root");
  }
  const configuredRoot = environment.PAPERCLIP_WORKSPACE_CWD?.trim();
  if (!configuredRoot) {
    throw new Error(
      "Remote Codex working directory requires an assigned workspace",
    );
  }
  if (
    !posix.isAbsolute(configuredRoot) ||
    posix.normalize(configuredRoot) !== configuredRoot
  ) {
    throw new Error(
      "Assigned remote workspace must be a normalized absolute path",
    );
  }
  // The controller cannot inspect a provider-owned filesystem. Pin the facade
  // to the exact remote workspace while runnerd validates existence, type, and
  // canonical identity inside the authoritative filesystem before launch.
  if (workingDirectory !== configuredRoot) {
    throw new Error(
      "Remote Codex working directory does not match the assigned workspace",
    );
  }
  return workingDirectory;
}

function canonicalConfiguredPath(value: string | undefined): string | null {
  const configured = value?.trim();
  if (!configured) return null;
  return canonicalPathWithMissingTail(resolve(configured));

View on GitHub (pinned to 01ad858492)

Solutions

  1. Set PAPERCLIP_WORKSPACE_CWD to a fully normalized absolute path with no trailing slash, e.g. "/workspaces/issue-42".
  2. Normalize before assigning: root = posix.normalize(posix.resolve(value)) in the code that sets the variable.
  3. Strip trailing slashes and collapse duplicate separators in whatever pipeline generates the env value.
  4. Verify the exact env value at startup with a fail-fast check before launching runners.

Example fix

// before
PAPERCLIP_WORKSPACE_CWD=/workspaces/issue-42/
// after
PAPERCLIP_WORKSPACE_CWD=/workspaces/issue-42  # absolute, no trailing slash, no // or . or ..
Defensive patterns

Strategy: validation

Validate before calling

const root = process.env.PAPERCLIP_WORKSPACE_CWD?.trim();
if (!root || !posix.isAbsolute(root) || posix.normalize(root) !== root) {
  throw new Error(`PAPERCLIP_WORKSPACE_CWD must be a normalized absolute path, got: ${root}`);
}

Type guard

const isNormalizedAbsolutePath = (p: unknown): p is string =>
  typeof p === "string" && posix.isAbsolute(p) && posix.normalize(p) === p;

Prevention

When it happens

Trigger: PAPERCLIP_WORKSPACE_CWD set to e.g. "workspaces/x" (relative), "/workspaces/x/" (trailing slash), "/workspaces//x", "/workspaces/./x", or "/workspaces/../x" while calling validateCodexWorkingDirectory(path, env, "remote_runner").

Common situations: Operator writing the env var by hand with a trailing slash; CI templating producing double slashes from joined strings; relative paths pasted from documentation; containers where HOME-relative shorthand was used instead of an absolute path.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/76389d723a614159. Report an issue: GitHub.