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
- Re-register the workspace using its canonical path: `paperclip register --cwd "$(realpath <dir>)"`.
- Remove the convenience symlink and operate on the real path.
- 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
- Store `realpath` output at registration time, never the raw user-supplied path.
- Refuse convenience symlinks for workspace roots in team docs.
- Log the canonical cwd at boot so alias drift is visible in logs.
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
- ${label} must be a canonical path and cannot use a symlink a
- Registered base project workspace Paperclip config at ${conf
- Registered base project workspace does not exist at ${resolv
- Registered base project workspace is not a directory at ${ca
- Registered source Paperclip config escapes the base project
AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-21).
Data as JSON: /api/errors/c4ad88e5f502fa18.
Report an issue: GitHub.