{"record":{"id":"eb7485d51aa126fd","repo":"toeverything/AFFiNE","slug":"space-access-denied-eb7485","errorCode":"space_access_denied","errorMessage":"You do not have permission to access Space ${spaceId}.","messagePattern":"You do not have permission to access Space (.+?)\\.","errorType":"exception","errorClass":"SpaceAccessDenied","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/core/workspaces/resolvers/member.ts","lineNumber":796,"sourceCode":"      workspaceId,\n      user.id,\n      WorkspaceRole.Collaborator,\n      {\n        status: WorkspaceMemberStatus.UnderReview,\n        source: WorkspaceMemberSource.Link,\n        inviterId: inviter.id,\n      }\n    );\n\n    await this.workspaceService.sendReviewRequestNotification(role.id);\n    this.event.emit('workspace.members.updated', { workspaceId });\n    return;\n  }\n\n  private async assertWorkspaceAcceptsMemberChange(workspaceId: string) {\n    const state = await this.policy.getWorkspaceState(workspaceId);\n    if (state.isReadonly) {\n      throw new SpaceAccessDenied({ spaceId: workspaceId });\n    }\n  }\n\n  private async allocateAvailableTeamSeats(workspaceId: string, limit: number) {\n    if (limit <= 0) return;\n    await this.workspaceService.allocateSeats(workspaceId, limit);\n  }\n}\n","sourceCodeStart":778,"sourceCodeEnd":805,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/49536827790702ad0ab6d3be3405d891a6b19f83/packages/backend/server/src/core/workspaces/resolvers/member.ts#L778-L805","documentation":"Thrown by assertWorkspaceAcceptsMemberChange when policy.getWorkspaceState(workspaceId).isReadonly is true. Member-changing operations (accepting invitations, join/leave) are blocked while the workspace is in a readonly policy state (e.g. billing suspended or admin-locked).","triggerScenarios":"Calling acceptInvitation (email or link path) or other member mutations on a workspace whose policy state is readonly.","commonSituations":"Self-hosted or cloud workspace suspended for overdue payment/expired trial; admin put the workspace in a locked state; the user retries an invitation accept while the lock is still active.","solutions":["Resolve the underlying state: the workspace owner should fix billing/subscription so the workspace exits readonly.","Retry the invitation acceptance after the workspace state returns to normal (the check re-evaluates each call).","If you believe the state is wrong, inspect the workspace policy/quota state records for stuck flags."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await acceptInvitation(inviteId);\n} catch (e) {\n  if (getErrorCode(e) === 'space_access_denied') {\n    // workspace is locked/readonly — have the owner fix billing, then the user can retry\n    showNotice('This workspace is currently read-only. Ask the owner to resolve billing, then retry.');\n  }\n}","preventionTips":["Treat space_access_denied during invitation acceptance as a temporary workspace state; retry after the owner restores the workspace.","Monitor workspace quota/policy state so readonly locks are caught before invitations are sent."],"tags":["workspace","readonly","policy","billing","invitation"],"backgroundTag":"workspace-readonly","analyzedSha":"49536827790702ad0ab6d3be3405d891a6b19f83","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}