paperclipai/paperclip · error · HttpError

workspace_repair_precondition_failed

workspace_repair_precondition_failed

Error message

Workspace repair requires a registered base project workspace.

What it means

Thrown by the execution-workspace repair action (POST /execution-workspaces/:id/repair) when the workspace being repaired has no registered base project workspace. The repair flow reseeds a managed worktree's .paperclip database from a seed source that must live inside a registered project workspace checkout, so a missing or cwd-less project workspace row makes repair impossible. It is rethrown as HTTP 422 with code workspace_repair_precondition_failed and reason source_registration_invalid. The projectWorkspace row is looked up from existing.projectWorkspaceId scoped to the same company and project, so a null result means either no projectWorkspaceId was set or the referenced row no longer matches that scope.

Source

Thrown at server/src/routes/execution-workspaces.ts:402

      const manifestPath = path.join(workspaceCwd, ".paperclip", "seed-manifest.json");
      let manifest: {
        attemptId?: unknown;
        source?: { configPath?: unknown; instanceId?: unknown };
        targetInstanceId?: unknown;
      };
      try {
        manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
      } catch {
        throw unprocessable("Workspace seed manifest is malformed; repair source identity cannot be trusted.", {
          code: "workspace_repair_precondition_failed",
          reason: "seed_manifest_malformed",
          repairPhase: "precondition_validation",
        });
      }

      try {
        if (!projectWorkspace?.cwd) {
          throw new Error("Workspace repair requires a registered base project workspace.");
        }
        const expectedTargetInstanceId = resolveManagedWorkspaceInstanceId(workspaceCwd);
        if (!expectedTargetInstanceId) {
          throw new Error("Workspace repair cannot resolve the registered target instance.");
        }
        repairSeedSource = resolveCanonicalWorktreeSeedSource({
          registeredBaseWorkspaceCwd: projectWorkspace.cwd,
          explicitSourceConfigPath: resolveFallbackSeedSourceConfigPath(projectWorkspace.cwd),
          targetConfigPath: path.join(workspaceCwd, ".paperclip", "config.json"),
          expectedTargetInstanceId,
          manifestSource: manifest.source,
          manifestTargetInstanceId: manifest.targetInstanceId,
        });
        repairPreviousAttemptId = typeof manifest.attemptId === "string" ? manifest.attemptId : null;

        const baseWorkspaceCwd = repairSeedSource.baseWorkspaceCwd;
        if (!baseWorkspaceCwd) {
          throw new Error("Workspace repair source is not bound to a registered base project workspace.");

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Check the execution workspace record: GET /api/execution-workspaces/:id and confirm projectWorkspaceId is set and non-null.
  2. Verify the project workspace row exists and has a cwd: query project_workspaces by that id within the same company/project scope and confirm cwd is a non-empty, existing directory.
  3. Re-register or fix the base project workspace (re-add the checkout so its cwd resolves), then retry the repair action.
  4. If the base checkout genuinely no longer exists, re-create the execution workspace from a healthy base instead of repairing it.

Example fix

// before
await api.post(`/api/execution-workspaces/${id}/repair`); // 422 workspace_repair_precondition_failed

// after
const ws = await api.getExecutionWorkspace(id);
if (!ws.projectWorkspaceId) throw new Error("Register a base project workspace before repair.");
const base = await api.getProjectWorkspace(ws.projectWorkspaceId);
if (!base?.cwd) throw new Error("Base project workspace has no cwd; re-register it.");
await api.post(`/api/execution-workspaces/${id}/repair`);
Defensive patterns

Strategy: validation

Validate before calling

const ws = await api.getExecutionWorkspace(id);
if (!ws.projectWorkspaceId) throw new Error("Execution workspace has no base project workspace; register one before repair.");
const base = await api.getProjectWorkspace(ws.projectWorkspaceId);
if (!base?.cwd || !existsSync(base.cwd)) throw new Error(`Base project workspace cwd missing or absent: ${base?.cwd}`);

Type guard

function isRepairReadyWorkspace(ws: { projectWorkspaceId: string | null }, base: { cwd: string | null } | null): boolean {
  return Boolean(ws.projectWorkspaceId && base?.cwd);
}

Try / catch

try {
  await api.post(`/api/execution-workspaces/${id}/repair`);
} catch (err) {
  if (err?.status === 422 && err.body?.details?.code === "workspace_repair_precondition_failed" && err.body?.details?.reason === "source_registration_invalid") {
    // re-register the base project workspace, then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the runtime command route with action="repair" on an execution workspace whose projectWorkspaceId is null, or whose project_workspaces row was deleted or has a null/empty cwd (the DB select at server/src/routes/execution-workspaces.ts:291-310 returns null or a row without cwd). Always fires before any operation row or service mutation.

Common situations: Execution workspace created from a project that never registered a local base checkout; the base project workspace was deleted or re-registered after the execution workspace was seeded; a worktree whose parent project workspace record lost its cwd after a move of the repo on disk; company/project scoping mismatch after data imports.

Related errors


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