{"record":{"id":"dc01a47caad0d156","repo":"nexu-io/open-design","slug":"workspace-project-permission-denied","errorCode":"WORKSPACE_PROJECT_PERMISSION_DENIED","errorMessage":"the reused project Workspace is no longer writable by this member","messagePattern":"the reused project Workspace is no longer writable by this member","errorType":"error_code","errorClass":"AutomationWorkspaceScopeError","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/automations/workspace-scope.ts","lineNumber":157,"sourceCode":"    );\n  }\n  return context;\n}\n\n/**\n * Resolve a reused project's persisted binding. The project row chooses the\n * Workspace; the signed-in directory supplies the current member and authority.\n */\nexport async function authorizePersistedProjectWorkspace(\n  workspaceIdInput: string,\n  fetchWorkspaceDirectory: (() => Promise<WorkspaceDirectoryFetchResult>) | undefined,\n): Promise<WorkspaceCollabContext> {\n  const workspaceId = workspaceIdInput.trim();\n  const items = await fetchDirectoryOrThrow(fetchWorkspaceDirectory);\n  const item = items.find((candidate) => candidate.workspaceId === workspaceId);\n  const context = activeWritableContext(item ? workspaceContextFromDirectoryItem(item) : null);\n  if (!context) {\n    throw new AutomationWorkspaceScopeError(\n      'WORKSPACE_PROJECT_PERMISSION_DENIED',\n      'the reused project Workspace is no longer writable by this member',\n      false,\n    );\n  }\n  return context;\n}\n","sourceCodeStart":139,"sourceCodeEnd":165,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/automations/workspace-scope.ts#L139-L165","documentation":"Thrown by authorizePersistedProjectWorkspace with code WORKSPACE_PROJECT_PERMISSION_DENIED and retryable=false. Same shape as error 27 but for the reused-project binding path: it looks the workspaceId up in the directory and requires activeWritableContext to succeed. The separate code lets callers branch project-reuse denials apart from automation-scope denials.","triggerScenarios":"Reusing a project whose workspace the member has since lost access to; the workspace was transferred or archived after the project binding was persisted.","commonSituations":"Project handover where the original owner's membership was revoked; cross-workspace project import that did not update the binding.","solutions":["Restore the member's write access to that workspace.","Rebind the project to a workspace the current member can write to, or fork the project into such a workspace.","Delete the stale reused-project binding if it is no longer relevant (retryable=false)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"async function projectWorkspaceStillWritable(fetcher: () => Promise<{ ok: boolean; items: Array<{ workspaceId: string; writable: boolean }> }>, workspaceId: string): Promise<boolean> {\n  const dir = await fetcher();\n  if (!dir.ok) return false;\n  const item = dir.items.find(i => i.workspaceId === workspaceId);\n  return Boolean(item && item.writable);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await authorizePersistedProjectWorkspace(workspaceId, fetcher);\n} catch (err) {\n  if (err instanceof AutomationWorkspaceScopeError && err.code === 'WORKSPACE_PROJECT_PERMISSION_DENIED') {\n    return forbidden('The reused project Workspace is no longer writable by this member.');\n  }\n  throw err;\n}","preventionTips":["Before reusing a project, verify the current member still has write access to its workspace.","When transferring project ownership, update or fork the binding in the same operation.","Branch on the WORKSPACE_PROJECT_PERMISSION_DENIED code separately from WORKSPACE_ACCESS_DENIED — they have different remediation paths."],"tags":["workspace","authz","project","permission"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}