toeverything/AFFiNE · warning · MentionUserDocAccessDenied
mention_user_doc_access_denied
mention_user_doc_access_denied
Error message
Mentioned user can not access doc ${docId}. What it means
MentionUserDocAccessDenied (code=mention_user_doc_access_denied) thrown by the mention mutation when the mentioned user lacks Doc.Read on the target doc. Mentions implicitly grant the recipient the ability to see the doc reference; if they can't read the doc, the mention is rejected. The check runs after the current user's Doc.Update is verified, so the author is allowed but the recipient is not.
Source
Thrown at packages/backend/server/src/core/notification/resolver.ts:71
createdByUserId: me.id,
},
});
if (parsedInput.userId === me.id) {
throw new MentionUserOneselfDenied();
}
// currentUser can update the doc
await this.ac
.user(me.id)
.doc(parsedInput.body.workspaceId, parsedInput.body.doc.id)
.assert('Doc.Update');
// mention user can read the doc
if (
!(await this.ac
.user(parsedInput.userId)
.doc(parsedInput.body.workspaceId, parsedInput.body.doc.id)
.can('Doc.Read'))
) {
throw new MentionUserDocAccessDenied({
docId: parsedInput.body.doc.id,
});
}
const notification = await this.service.createMention(parsedInput);
return notification.id;
}
@Mutation(() => Boolean, {
description: 'mark notification as read',
})
async readNotification(
@CurrentUser() me: UserType,
@Args('id') notificationId: string
) {
await this.service.markAsRead(me.id, notificationId);
return true;
}
View on GitHub (pinned to 26c515e050)
Solutions
- Source the mention autocomplete from users who can read the doc (intersect with the doc's readable-users list) rather than all workspace members.
- Offer to grant Doc.Read to the mentioned user as part of the mention action, then retry.
- On this error, prompt the author to share the doc with the user first.
- Surface the docId from the error payload so the client can show which doc is the blocker.
Example fix
// before
if (!(await this.ac.user(parsedInput.userId).doc(ws, doc).can('Doc.Read'))) {
throw new MentionUserDocAccessDenied({ docId: parsedInput.body.doc.id });
}
// client side — only offer mentionable users who can already read the doc
const mentionable = await fetchUsersWhoCanRead(ws, doc.id);
// or: grant read as part of the mention flow
await grantDocRead(ws, doc.id, mentionedUserId);
await mention(...); Defensive patterns
Strategy: validation
Validate before calling
async function assertMentionCanRead(ac, ws, doc, targetId) {
const ok = await ac.user(targetId).doc(ws, doc).can('Doc.Read');
if (!ok) throw new UserError(`User ${targetId} cannot read doc ${doc}; share first`);
} Type guard
function isMentionAccessDenied(e: unknown): boolean {
return e instanceof Error && (e as any).code === 'mention_user_doc_access_denied';
} Try / catch
try {
await resolver.createMention(me, input);
} catch (e) {
if (isMentionAccessDenied(e)) {
return promptShareDoc(e.docId); // offer to grant Doc.Read, then retry
}
throw e;
} Prevention
- Source mention candidates from users who can read the doc.
- Offer to grant Doc.Read as part of the mention action.
- Use the docId in the error payload to show which doc is blocked.
When it happens
Trigger: Mentioning an external/guest user on a doc restricted to workspace members, or a user from another workspace, or a user whose role was downgraded. Mentioning on a doc shared with a subset that excludes the target.
Common situations: Doc permission scope is narrower than the mention autocomplete source (autocomplete shows all workspace users, doc is member-restricted). Mentioning a user who left the workspace. Cross-workspace mention attempts.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/3a0a8be37de56e3b.
Report an issue: GitHub.