nexu-io/open-design · error · CreatedProjectWorkspaceResolutionError
WORKSPACE_PROJECT_PERMISSION_DENIED
WORKSPACE_PROJECT_PERMISSION_DENIED
Error message
workspace project creation is not allowed
What it means
Thrown by createdProjectWorkspaceHome as a CreatedProjectWorkspaceResolutionError carrying code WORKSPACE_PROJECT_PERMISSION_DENIED and HTTP status 403. It fires after authorizeCreatedProjectWorkspace resolves to a denied state: the requesting member is not 'active', lacks canWriteSyncedFiles, the workspace resource is locked, or the (workspaceId, workspaceMemberId) pair is not present in the authoritative membership directory. The resolver intentionally fails closed rather than silently creating an unbound project once any workspace identity is asserted.
Source
Thrown at apps/daemon/src/collab/created-project-workspace.ts:189
this.name = 'CreatedProjectWorkspaceResolutionError';
this.status = error.status;
this.code = error.code;
if (error.retryable) this.retryable = true;
}
}
/**
* Resolve an exact creation scope. Headerless legacy requests remain unbound.
* Once either identity field is asserted, any incomplete, removed, denied, or
* unavailable authority fails closed; it never degrades to ambient/current or
* silently creates an unbound project.
*/
export async function createdProjectWorkspaceHome(
req: unknown,
fetchWorkspaceDirectory?: () => Promise<WorkspaceDirectoryFetchResult>,
): Promise<WorkspaceResourceContext | null> {
const authorized = await authorizeCreatedProjectWorkspace(req, fetchWorkspaceDirectory);
if (!authorized.ok) throw new CreatedProjectWorkspaceResolutionError(authorized);
return authorized.context;
}
/**
* A `createdProjectWorkspaceHome` bound to one daemon's authorities, so a route
* module takes a single dep instead of re-threading three.
*/
export type CreatedProjectWorkspaceResolver = (
req: unknown,
) => Promise<WorkspaceResourceContext | null>;
export function createCreatedProjectWorkspaceResolver(deps: {
fetchWorkspaceDirectory?: () => Promise<WorkspaceDirectoryFetchResult>;
}): CreatedProjectWorkspaceResolver {
return (req) =>
createdProjectWorkspaceHome(
req,
deps.fetchWorkspaceDirectory,View on GitHub (pinned to 5be4028344)
Solutions
- Verify the user's membership and role in the target team (active member with write permission).
- Re-authenticate / refresh the workspace directory so headers reflect current membership.
- Retry when the workspace is no longer locked, if the lock was the cause.
- If a personal (unbound) project is acceptable, create it without workspace identity headers — headerless legacy requests remain unbound by design.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check membership before creating a bound project.
const resolution = await authorizeCreatedProjectWorkspace(req, fetchWorkspaceDirectory);
if (!resolution.ok && resolution.code === 'WORKSPACE_PROJECT_PERMISSION_DENIED') {
// surface 403 to the user, or fall back to a headerless personal create
} Type guard
function isPermissionDenied(err: unknown): boolean {
return err instanceof Error && (err as { code?: string }).code === 'WORKSPACE_PROJECT_PERMISSION_DENIED';
} Try / catch
import { CreatedProjectWorkspaceResolutionError } from './created-project-workspace.js';
try {
await createdProjectWorkspaceHome(req, fetchWorkspaceDirectory);
} catch (err) {
if (err instanceof CreatedProjectWorkspaceResolutionError && err.code === 'WORKSPACE_PROJECT_PERMISSION_DENIED') {
// return 403 to the client, or retry without workspace headers for a personal project
}
throw err;
} Prevention
- Refresh the workspace directory before creation so membership/role is current.
- Only assert workspace headers when you genuinely want a bound (team) project.
- For personal projects, omit workspace identity headers — headerless requests stay unbound by design.
When it happens
Trigger: A project-creation request carrying workspace/member headers from a user whose membership was revoked or suspended, whose role cannot write synced files, whose resource is locked, or who is not in the directory at all. Also when the directory fetch returns a membership that fails the active+write+unlocked re-check.
Common situations: Membership revoked mid-session (token still cached locally), a read-only/viewer role trying to create a synced project, a locked workspace during maintenance, or stale headers after a workspace switch.
Related errors
- workspace_resource_share_denied
- workspaceId is required
- design system backing project is unavailable
- design system backing project belongs to another workspace
- workspace_resource_share_denied
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/4959e7f5be939430.
Report an issue: GitHub.