paperclipai/paperclip · error
Project workspace not found
Error message
Project workspace not found
What it means
HTTP 404 from handleProjectWorkspaceRuntimeCommand when the workspaceId in the URL does not match any workspace of the project loaded by svc.getById(id). The project itself was found (otherwise 'Project not found'), but the workspace sub-resource is absent, so the handler stops before the authorization check.
Source
Thrown at server/src/routes/projects.ts:449
res.json(workspace);
},
);
async function handleProjectWorkspaceRuntimeCommand(req: Request, res: Response) {
const id = req.params.id as string;
const workspaceId = req.params.workspaceId as string;
const action = String(req.params.action ?? "").trim().toLowerCase();
if (action !== "start" && action !== "stop" && action !== "restart" && action !== "run") {
res.status(404).json({ error: "Workspace command action not found" });
return;
}
const project = await getAccessibleResource(req, res, svc.getById(id), "Project not found");
if (!project) return;
const workspace = project.workspaces.find((entry) => entry.id === workspaceId) ?? null;
if (!workspace) {
res.status(404).json({ error: "Project workspace not found" });
return;
}
if (!(await assertRuntimeManageAllowed(req, res, project.companyId))) return;
const isSharedWorkspace = Boolean(workspace.sharedWorkspaceKey);
if (
req.actor.type === "agent"
&& isSharedWorkspace
&& SHARED_WORKSPACE_STOP_AND_RESTART_ACTIONS.has(action)
) {
throw forbidden("Missing permission to manage workspace runtime services");
}
await assertCanManageProjectWorkspaceRuntimeServices(db, req, {
companyId: project.companyId,
projectWorkspaceId: workspace.id,
});
View on GitHub (pinned to 01ad858492)
Solutions
- Re-fetch the project (GET /api/projects/:id) and use a workspaceId from its current workspaces list.
- Confirm the workspaceId belongs to the same project as the :id path parameter.
- Recreate the workspace if it was intentionally deleted, then retry with the new ID.
- If the workspace exists but isn't returned, check company scoping/filters on the service's getById (actor may not see it).
Example fix
// before
POST /api/projects/p1/workspaces/w_old/runtime/restart // 404 Project workspace not found
// after
const project = await fetch('/api/projects/p1').then(r => r.json());
const wId = project.workspaces[0].id; // use a live workspace id
POST `/api/projects/p1/workspaces/${wId}/runtime/restart` Defensive patterns
Strategy: validation
Validate before calling
const project = await getProject(projectId);
const workspace = project?.workspaces?.find(w => w.id === workspaceId);
if (!workspace) throw new Error(`workspace ${workspaceId} not found in project ${projectId}`); Type guard
function workspaceExists(project, workspaceId) {
return Boolean(project && Array.isArray(project.workspaces) && project.workspaces.some(w => w && w.id === workspaceId));
} Try / catch
try {
return await postRuntimeCommand(projectId, workspaceId, cmd);
} catch (e) {
if (isNotFound(e)) {
const fresh = await refreshProject(projectId); // re-list workspaces
return postRuntimeCommand(projectId, fresh.workspaces[0].id, cmd);
}
throw e;
} Prevention
- Always re-fetch the project before issuing workspace-scoped commands.
- Never cache workspaceIds across sessions or project deletions.
- Verify workspaceId and projectId come from the same parent object.
- Handle 404 by refreshing the workspace list instead of retrying blindly.
When it happens
Trigger: Calling a project workspace runtime command endpoint with a stale/deleted workspaceId, a workspaceId belonging to a different project, or a typo'd ID — project.workspaces.find(entry => entry.id === workspaceId) returns null.
Common situations: Workspace was deleted after the client cached its ID; client mixes IDs across projects; concurrent project update removed the workspace; copy-paste of workspaceId from another project.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Job not found
- ${name} must be a JSON object
- Invalid ${name} JSON: ${err instanceof Error ? err.message :
- --file is required
- Request failed with status ${response.status}
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/891251cec6667c06.
Report an issue: GitHub.