paperclipai/paperclip · error · Error

Registered base project workspace is not a directory at ${ca

Error message

Registered base project workspace is not a directory at ${canonicalBaseCwd}.

What it means

The registered base workspace cwd resolves fine but lstat says it is not a directory (a regular file, FIFO, etc.). A base workspace must be a directory because the resolver looks for `.paperclip/config.json` inside it and uses it to anchor worktrees.

Source

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

    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");
  if (registeredConfigPath && canonicalSourceConfigPath !== registeredConfigPath) {
    throw new Error("Registered source Paperclip config escapes the base project workspace or uses a symlink alias.");
  }

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Inspect what is at the path: `ls -la <canonicalBaseCwd>` / `file <canonicalBaseCwd>`.
  2. If a file occupies the path, remove/rename it and restore the actual workspace directory.
  3. Re-register pointing at the checkout's root directory, not at any file inside it.

Example fix

# before
paperclip register --cwd ~/code/myproj/.paperclip/config.json   # a file

# after
paperclip register --cwd ~/code/myproj
Defensive patterns

Strategy: validation

Validate before calling

import { statSync } from "node:fs";

const st = statSync(input.registeredBaseWorkspaceCwd!.trim());
if (!st.isDirectory()) throw new Error("registered base workspace must be a directory");

Type guard

const isDirectory = (p: string): boolean => {
  try { return statSync(p).isDirectory(); } catch { return false; }
};

Prevention

When it happens

Trigger: registering a workspace whose cwd is actually a file (e.g. a config or script path passed instead of its directory); a special node placed at the recorded path; a path that changed from directory to file after registration.

Common situations: Passing a path with a trailing `/config.json` to a registration command; provisioning scripts creating a marker file where the directory should be; artifacts unpacked over the workspace path.

Related errors


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