{"record":{"id":"13de81e7c7425289","repo":"toeverything/AFFiNE","slug":"workspace-permission-not-found","errorCode":"workspace_permission_not_found","errorMessage":"Space ${spaceId} permission not found.","messagePattern":"Space (.+?) permission not found\\.","errorType":"exception","errorClass":"WorkspacePermissionNotFound","httpStatus":404,"severity":"error","filePath":"packages/backend/server/src/plugins/indexer/service.ts","lineNumber":151,"sourceCode":"    for (const doc of docs) {\n      doc.createdByUser = users.get(doc.createdByUserId);\n      doc.updatedByUser = users.get(doc.updatedByUserId);\n    }\n    return docs;\n  }\n\n  private unwrap<T>(output: SearchOperationOutput, workspaceId: string): T {\n    if (output.ok) return output.value as T;\n    switch (output.errorCode) {\n      case 'workspace_denied':\n        throw new SpaceAccessDenied({ spaceId: workspaceId });\n      case 'invalid_request':\n      case 'unsupported_query':\n        throw new InvalidIndexerInput({ reason: output.errorCode });\n      case 'provider_unavailable':\n        throw new SearchProviderNotFound();\n      case 'permission_unavailable':\n        throw new WorkspacePermissionNotFound({ spaceId: workspaceId });\n      default:\n        throw new InternalServerError();\n    }\n  }\n}\n","sourceCodeStart":133,"sourceCodeEnd":157,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/591f874dad30887a80143a061a44bd3ca7ee3299/packages/backend/server/src/plugins/indexer/service.ts#L133-L157","documentation":"unwrap maps errorCode 'permission_unavailable' to WorkspacePermissionNotFound, carrying the workspaceId. Unlike 'workspace_denied', this means the permission subsystem could not answer the access question at all while executing the search — the decision is unknown, not 'no'.","triggerScenarios":"The permission lookup backing the search operation fails or finds no permission records for the workspace while a search is in flight.","commonSituations":"Permission storage (DB/service) briefly unreachable; workspace permission rows missing after a partial migration or data corruption; deployments where the permission service and indexer are scaled independently and one is down.","solutions":["Check server logs and health of the permission storage backing the search operation","Verify the workspace exists and actually has permission records","Retry once — transient storage errors surface through this code path"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-flight the permission store before searching\nconst healthy = await permissionService.ping();\nif (!healthy) return serviceUnavailable('permission storage unavailable');\nreturn indexerService.search(user, { workspaceId, query });","typeGuard":null,"tryCatchPattern":"// unknown-decision errors are transient: one bounded retry\ntry {\n  return await search(user, workspaceId, query);\n} catch (e) {\n  if (e instanceof WorkspacePermissionNotFound) {\n    await sleep(500);\n    return search(user, workspaceId, query); // single retry, then surface 503\n  }\n  throw e;\n}","preventionTips":["Monitor permission-storage errors separately from explicit denials — they need different response codes (503 vs 403)","Alert when 'permission_unavailable' rate rises; it precedes user-visible search outages"],"tags":["indexer","search","permission","workspace","availability"],"backgroundTag":"permission-lookup-failed","analyzedSha":"591f874dad30887a80143a061a44bd3ca7ee3299","analyzedAt":"2026-08-21T18:20:45.039Z","contentChangedAt":"2026-08-21T18:20:45.039Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}