paperclipai/paperclip · error · Error
${label} must be a canonical path and cannot use a symlink a
Error message
${label} must be a canonical path and cannot use a symlink alias. What it means
canonicalRegularFile() requires that `path.resolve(p)` equal `realpathSync(p)` and that the path itself not be a symlink. If realpath resolves through any symlink component, or lstat on the resolved path reports a link, the config is considered a non-canonical alias and rejected, because identity checks later compare raw path strings.
Source
Thrown at packages/shared/src/worktree-seed-source.ts:106
} catch (error) {
throw new Error(
`Registered base project workspace Paperclip config at ${configPath} cannot be inspected (${errorCode(error)} on its .paperclip symlink target).`,
);
}
}
return false;
}
function canonicalRegularFile(filePath: string, label: string): string {
const resolved = path.resolve(filePath);
let canonical: string;
try {
canonical = realpathSync(resolved);
} catch {
throw new Error(`${label} does not exist at ${resolved}.`);
}
if (canonical !== resolved || lstatSync(resolved).isSymbolicLink()) {
throw new Error(`${label} must be a canonical path and cannot use a symlink alias.`);
}
if (!lstatSync(canonical).isFile()) {
throw new Error(`${label} is not a regular file at ${canonical}.`);
}
return canonical;
}
/** Resolve the authoritative source and target identities without consulting diagnostics. */
export function resolveRegisteredWorktreeSeedSource(
input: RegisteredWorktreeSeedSourceInput,
): CanonicalWorktreeSeedSource {
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.",
);
}View on GitHub (pinned to a7e689b3c3)
Solutions
- Use the fully resolved path: pass `$(realpath <config>)` output instead of the alias.
- Remove the symlink and pass the real file path directly.
- Re-register the base workspace using its canonical (realpath) cwd so derived paths are canonical too.
- On macOS, beware /tmp → /private/tmp; anchor configs under a non-linked directory.
Example fix
# before paperclip worktree seed --from-config /tmp/pc/config.json # /tmp is a symlink on macOS # after paperclip worktree seed --from-config "$(realpath /tmp/pc/config.json)"
Defensive patterns
Strategy: validation
Validate before calling
import { lstatSync, realpathSync } from "node:fs";
import path from "node:path";
function isCanonicalRegularFile(p: string): boolean {
const resolved = path.resolve(p);
try {
if (realpathSync(resolved) !== resolved) return false;
if (lstatSync(resolved).isSymbolicLink()) return false;
return lstatSync(resolved).isFile();
} catch { return false; }
} Type guard
const isCanonicalPath = (p: string): boolean => {
try { return realpathSync(p) === path.resolve(p); } catch { return false; }
}; Try / catch
try {
resolveRegisteredWorktreeSeedSource(input);
} catch (e) {
if (e instanceof Error && e.message.includes("cannot use a symlink alias")) {
input.explicitSourceConfigPath = realpathSync(input.explicitSourceConfigPath!); // normalize then retry
} else throw e;
} Prevention
- Canonicalize once at input boundaries: store `realpathSync(p)` results, pass those onward.
- On macOS, avoid /tmp and other system aliases for config paths.
- Add a lint/CI check that registration and manifest paths pass a realpath-equals-input assertion.
When it happens
Trigger: Passing a config path that is itself a symlink (`ln -s real.json alias.json`, then --from-config alias.json); paths containing symlinked directories such as macOS `/tmp` vs `/private/tmp` or a symlinked home directory; workspace checked out under a linked path.
Common situations: macOS temp/home dir aliasing; users shortening long instance paths with symlinks; CI runners where HOME or the checkout root is a link; Nix/store-style symlinked prefixes.
Related errors
- Registered base project workspace Paperclip config at ${conf
- Registered base project workspace must be canonical and cann
- ${label} does not exist at ${resolved}.
- ${label} is not a regular file at ${canonical}.
- Registered base project workspace does not exist at ${resolv
AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-21).
Data as JSON: /api/errors/95bf30df47dd3dad.
Report an issue: GitHub.