{"record":{"id":"8fbe0139127d3917","repo":"toeverything/AFFiNE","slug":"access-denied-8fbe01","errorCode":"access_denied","errorMessage":"You do not have permission to access this resource.","messagePattern":"You do not have permission to access this resource\\.","errorType":"exception","errorClass":"AccessDenied","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/plugins/payment/resolver.ts","lineNumber":577,"sourceCode":"\n  private subscriptionPlan(plan: string) {\n    return plan === 'lifetime_pro' ? SubscriptionPlan.Pro : plan;\n  }\n\n  private subscriptionStatus(entitlement: Entitlement) {\n    if (entitlement.status === 'grace') {\n      return SubscriptionStatus.PastDue;\n    }\n    return SubscriptionStatus.Active;\n  }\n\n  @ResolveField(() => [SubscriptionType])\n  async subscriptions(\n    @CurrentUser() me: User,\n    @Parent() user: User\n  ): Promise<Subscription[]> {\n    if (me.id !== user.id) {\n      throw new AccessDenied();\n    }\n\n    return this.currentUserSubscriptions(user.id);\n  }\n\n  @ResolveField(() => Int, {\n    name: 'invoiceCount',\n    description: 'Get user invoice count',\n  })\n  async invoiceCount(@CurrentUser() user: CurrentUser) {\n    return this.db.invoice.count({\n      where: { targetId: user.id },\n    });\n  }\n\n  @ResolveField(() => [InvoiceType])\n  async invoices(\n    @CurrentUser() me: User,","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/payment/resolver.ts#L559-L595","documentation":"Thrown by the User.subscriptions GraphQL field resolver when the authenticated user (from @CurrentUser) is not the same user as the @Parent User object being resolved. It is an ownership check: subscription lists are private and can only be resolved for yourself.","triggerScenarios":"Querying user(id: X) { subscriptions } where X is any id other than the signed-in user's id; resolving subscriptions on a user object obtained from a nested relation (e.g. workspace member list) instead of the currentUser query.","commonSituations":"Admin dashboards trying to list another user's subscriptions; frontend nesting { subscriptions } under a member/owner field of a workspace query; stale auth token for user A while the page renders user B's profile.","solutions":["Request subscriptions only on the currentUser query or on user(id: <your own id>).","Move the subscriptions field out of nested/other-user selections in your GraphQL documents.","If you genuinely need another user's subscriptions (support tooling), use a server-side/admin API rather than this field."],"exampleFix":"# before\nquery {\n  user(id: \"someone-else\") { subscriptions { ... } }\n}\n\n# after\nquery {\n  currentUser { subscriptions { ... } }\n}","handlingStrategy":"validation","validationCode":"// Only request subscriptions for the signed-in user\nconst { data } = await gql(`query { currentUser { id subscriptions { ... } } }`);","typeGuard":null,"tryCatchPattern":"catch (e) { if (gqlErrorCode(e) === 'access_denied') { clearNestedSubscriptionsSelection(); refetchAsCurrentUser(); return; } throw e; }","preventionTips":["Restrict the subscriptions field to currentUser queries in your query documents.","Lint persisted operations for subscriptions under non-currentUser user fields.","Treat access_denied on this field as a document bug, not a runtime condition to retry."],"tags":["payment","authorization","graphql","ownership-check","security"],"backgroundTag":"permission-denied","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}