toeverything/AFFiNE · error · ActionForbidden
action_forbidden
action_forbidden
Error message
You are not allowed to perform this action.
What it means
AdminGuard.canActivate (admin-guard.ts:30) throws ActionForbidden when the request's session user is not a platform administrator: allow stays false either because req.session is missing (unauthenticated/internal call) or feature.isAdmin(req.session.user.id) resolves false. It guards admin-only routes/queries/mutations with a hard 403-style failure.
Solutions
- Sign in as a user flagged as administrator (instance-level admin, not merely workspace owner).
- For self-hosted, add the user to the admin allowlist/flag in the feature/admin configuration and retry.
- If you do not need admin features, call the regular non-guarded endpoint instead.
Defensive patterns
Strategy: validation
Validate before calling
// server-side: check admin status before building admin responses
const isAdmin = req.session ? await featureService.isAdmin(req.session.user.id) : false;
if (!isAdmin) {
return forbiddenFallback(); // hide admin entry points instead of triggering the guard
} Type guard
function isAdminForbidden(e: unknown): boolean {
return (
e instanceof GraphQLError &&
(e.extensions?.code === 'action_forbidden' ||
(e as HttpException)?.status === 403)
);
} Try / catch
try {
await adminMutation(input);
} catch (e) {
if (isAdminForbidden(e)) {
// hide admin UI and inform the user admin rights are required; never retry
} else throw e;
} Prevention
- Gate admin UI/features on a session admin flag fetched up front.
- Remember this is instance-level admin, not workspace owner.
- On self-hosted, ensure the admin user is flagged before wiring admin clients/scripts.
When it happens
Trigger: Calling any resolver/controller decorated with this admin guard while logged in as a non-admin user, or with no session at all; also when FeatureService is unavailable so isAdmin cannot confirm.
Common situations: Trying an admin GraphQL mutation or admin REST route from a normal member account on a self-hosted instance; scripts hitting admin endpoints with expired/missing auth; assuming workspace owner implies platform admin (it does not - this is instance-level admin).
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
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/e3c1067412edd8c9.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/common/admin-guard.ts:30
@Injectable()
export class AdminGuard implements CanActivate, OnModuleInit {
private feature!: FeatureService;
constructor(private readonly ref: ModuleRef) {}
onModuleInit() {
this.feature = this.ref.get(FeatureService, { strict: false });
}
async canActivate(context: ExecutionContext) {
const { req } = getRequestResponseFromContext(context);
let allow = false;
if (req.session) {
allow = await this.feature.isAdmin(req.session.user.id);
}
if (!allow) {
throw new ActionForbidden();
}
return true;
}
}
/**
* This guard is used to protect routes/queries/mutations that require a user to be administrator.
*
* @example
*
* ```typescript
* \@Admin()
* \@Mutation(() => UserType)
* createAccount(userInput: UserInput) {
* // ...
* }
* ```View on GitHub (pinned to b4c8548c09)