toeverything/AFFiNE · error · AccessDenied
access_denied
access_denied
Error message
You do not have permission to access this resource.
What it means
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.
Source
Thrown at packages/backend/server/src/plugins/payment/resolver.ts:577
private subscriptionPlan(plan: string) {
return plan === 'lifetime_pro' ? SubscriptionPlan.Pro : plan;
}
private subscriptionStatus(entitlement: Entitlement) {
if (entitlement.status === 'grace') {
return SubscriptionStatus.PastDue;
}
return SubscriptionStatus.Active;
}
@ResolveField(() => [SubscriptionType])
async subscriptions(
@CurrentUser() me: User,
@Parent() user: User
): Promise<Subscription[]> {
if (me.id !== user.id) {
throw new AccessDenied();
}
return this.currentUserSubscriptions(user.id);
}
@ResolveField(() => Int, {
name: 'invoiceCount',
description: 'Get user invoice count',
})
async invoiceCount(@CurrentUser() user: CurrentUser) {
return this.db.invoice.count({
where: { targetId: user.id },
});
}
@ResolveField(() => [InvoiceType])
async invoices(
@CurrentUser() me: User,View on GitHub (pinned to b4c8548c09)
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.
Example fix
# before
query {
user(id: "someone-else") { subscriptions { ... } }
}
# after
query {
currentUser { subscriptions { ... } }
} Defensive patterns
Strategy: validation
Validate before calling
// Only request subscriptions for the signed-in user
const { data } = await gql(`query { currentUser { id subscriptions { ... } } }`); Try / catch
catch (e) { if (gqlErrorCode(e) === 'access_denied') { clearNestedSubscriptionsSelection(); refetchAsCurrentUser(); return; } throw e; } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- invalid_invitation
- action_forbidden
- space_access_denied
- workspace_id_required_to_update_team_subscription
- action_forbidden
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/8fbe0139127d3917.
Report an issue: GitHub.