paperclipai/paperclip · error · WorkspaceValidationFailure
fallback_agent_home_cwd
fallback_agent_home_cwd
Error message
Issue ${issue.identifier ?? issue.id} expected a project workspace, but ${input.adapterType} would launch from agent fallback cwd "${effectiveCwd}". What it means
The issue's execution policy expects a project workspace, but the resolved effective cwd is the agent's default fallback directory, meaning no project workspace was attached or restorable for this adapter launch. The guard catches this before the agent starts in the wrong location.
Solutions
- Configure the project workspace so the adapter launches from it instead of the agent fallback cwd.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at server/src/services/heartbeat.ts:2134 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-18).
Data as JSON: /api/errors/378d94bf76cdc24e.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/heartbeat.ts:2549
// Preserve the closed failure code without copying subprocess output or
// credentials into the durable run. Setup recovery needs the actual cause.
if (isWorkspaceGitScanError(error)) throw new WorkspaceGitScanError(error.code, message);
throw new Error(message);
}
try {
await fs.rename(cloneTmpDir, cwd);
} catch (renameError) {
await fs
.rm(cloneTmpDir, { recursive: true, force: true })
.catch(() => undefined);
// The target appearing between the emptiness check and the rename means another
// materialization won the race; adopt its checkout instead of failing the run.
if (await hasAdoptableGitDir()) {
return { cwd, warning: null };
}
const reason =
renameError instanceof Error ? renameError.message : String(renameError);
throw new Error(
`Failed to move managed checkout into place at "${cwd}": ${reason}`,
);
}
return { cwd, warning: null };
}
/** Keep every distinct project repository inside the task's writable/synced root. */
export async function prepareProjectRepositoryWorkspaces(input: {
cwd: string;
anchorRepoUrl: string | null;
workspaces: Array<Pick<typeof projectWorkspaces.$inferSelect, "id" | "repoUrl" | "repoRef"> & { cwd?: string | null }>;
resolveGitAuth?: GitRemoteAuthProvider | null;
}): Promise<Array<{ workspaceId: string; cwd: string; repoUrl: string; repoRef: string | null }>> {
const identity = (url: string) => url.trim().replace(/\.git\/?$/, "").replace(/\/$/, "");
const seen = new Set(input.anchorRepoUrl ? [identity(input.anchorRepoUrl)] : []);
const selected = input.workspaces.filter((workspace) => {
if (!workspace.repoUrl || seen.has(identity(workspace.repoUrl))) return false;View on GitHub (pinned to 3f1d897a7c)