paperclipai/paperclip · error · Error

Registered base project workspace must be canonical and cann

Error message

Registered base project workspace must be canonical and cannot use a symlink alias.

What it means

The registered base workspace cwd exists, but realpathSync(resolved) differs from the resolved input, meaning the cwd reaches through a symlink alias. Downstream identity checks compare canonical strings, so the registration must already be canonical; an alias would let the same physical workspace be treated as two different ones.

Source

Thrown at packages/shared/src/worktree-seed-source.ts:136

  const registeredCwd = input.registeredBaseWorkspaceCwd?.trim();
  const explicitSource = input.explicitSourceConfigPath?.trim();
  if (!registeredCwd && !explicitSource) {
    throw new Error(
      "Worktree seed source is not registered. Managed boot requires a project workspace; manual boot requires --from-config.",
    );
  }

  let canonicalBaseCwd: string | null = null;
  let registeredConfigPath: string | null = null;
  if (registeredCwd) {
    const resolvedRegisteredCwd = path.resolve(registeredCwd);
    try {
      canonicalBaseCwd = realpathSync(resolvedRegisteredCwd);
    } catch {
      throw new Error(`Registered base project workspace does not exist at ${resolvedRegisteredCwd}.`);
    }
    if (canonicalBaseCwd !== resolvedRegisteredCwd) {
      throw new Error("Registered base project workspace must be canonical and cannot use a symlink alias.");
    }
    if (!lstatSync(canonicalBaseCwd).isDirectory()) {
      throw new Error(`Registered base project workspace is not a directory at ${canonicalBaseCwd}.`);
    }
    // A base workspace that is a plain checkout carries no instance config of its own.
    // The caller's explicit source supplies it, and stays subject to every check below.
    registeredConfigPath = baseWorkspaceDeclaresInstanceConfig(canonicalBaseCwd)
      ? path.join(canonicalBaseCwd, ".paperclip", "config.json")
      : null;
  }

  const selectedPath = registeredConfigPath ?? explicitSource;
  if (!selectedPath) {
    throw new Error(
      "Registered base project workspace has no Paperclip config of its own and no explicit source was provided.",
    );
  }
  const canonicalSourceConfigPath = canonicalRegularFile(selectedPath, "Registered source Paperclip config");

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Re-register the workspace using its canonical path: `paperclip register --cwd "$(realpath <dir>)"`.
  2. Remove the convenience symlink and operate on the real path.
  3. Check `realpath <cwd>` vs the stored registration and make them byte-identical.

Example fix

# before (macOS)
paperclip register --cwd /tmp/scratch/myproj   # /tmp -> /private/tmp

# after
paperclip register --cwd "$(realpath /tmp/scratch/myproj)"
Defensive patterns

Strategy: validation

Validate before calling

import { realpathSync } from "node:fs";
import path from "node:path";

const cwd = input.registeredBaseWorkspaceCwd!.trim();
const resolved = path.resolve(cwd);
if (realpathSync(resolved) !== resolved) {
  input = { ...input, registeredBaseWorkspaceCwd: realpathSync(resolved) }; // normalize before calling
}

Type guard

const isCanonicalDir = (p: string): boolean => {
  try { return realpathSync(p) === path.resolve(p); } catch { return false; }
};

Try / catch

try {
  resolveRegisteredWorktreeSeedSource(input);
} catch (e) {
  if (e instanceof Error && /must be canonical/.test(e.message)) {
    input.registeredBaseWorkspaceCwd = realpathSync(input.registeredBaseWorkspaceCwd!);
    return resolveRegisteredWorktreeSeedSource(input); // one retry with canonical path
  }
  throw e;
}

Prevention

When it happens

Trigger: Registering a workspace via a symlinked path (e.g. /tmp on macOS resolving to /private/tmp, a linked home dir, or a shortcut link to the real checkout) and then booting worktree seed resolution from it.

Common situations: macOS /tmp and /var aliases; `ln -s ~/real/project ~/shortcut` used for convenience; HOME itself a symlink; CI checkouts under linked directories; Nix-style symlink trees.

Related errors


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-21). Data as JSON: /api/errors/c4ad88e5f502fa18. Report an issue: GitHub.