toeverything/AFFiNE · warning · MentionUserOneselfDenied

mention_user_oneself_denied

mention_user_oneself_denied

Error message

You can not mention yourself.

What it means

The createMention mutation parses MentionNotificationCreateSchema and immediately rejects self-mentions: if input.userId equals the authenticated user's id (me.id) it throws MentionUserOneselfDenied (action_forbidden / mention_user_oneself_denied). Mentioning yourself is pointless because you are the notification recipient and the mention author at the same time.

Solutions

  1. Filter the current user out of mention suggestions in the UI before submission
  2. Guard client-side: skip the createMention call when selectedUserId === currentUser.id
  3. Show a hint ('You cannot mention yourself') when a self-mention is attempted in the picker
  4. On catch, remove the self-mention from the doc's mention list and continue publishing

Example fix

// before
if (mentionedUserIds.includes(me.id)) await createMention({ userId: me.id, ... });

// after
const others = mentionedUserIds.filter(id => id !== me.id);
for (const userId of others) await createMention({ userId, ... });
Defensive patterns

Strategy: validation

Validate before calling

if (mentionUserId === me.id) {
  return showHint('You cannot mention yourself');
}
await createMention({ userId: mentionUserId, body });

Type guard

function isMentionOneselfDenied(e: unknown): boolean {
  return (e as { extensions?: { code?: string } }).extensions?.code === 'mention_user_oneself_denied';
}

Try / catch

try {
  await createMention(input);
} catch (e) {
  if (isMentionOneselfDenied(e)) return; // silently drop self-mention
  throw e;
}

Prevention

When it happens

Trigger: The mention picker returning the current user (search matches on your own name) and the client sending it; automated doc-processing that @-mentions every contributor including the author; UI tests that pick the first suggestion without filtering.

Common situations: Frontend mention dropdowns that don't exclude 'self' from candidate results; keyboard shortcut flows that auto-complete the top match; older clients predating this server-side check.

Related errors


AI-assisted analysis of toeverything/AFFiNE@591f874dad (2026-08-18). Data as JSON: /api/errors/1e264b6f13df160b. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/core/notification/resolver.ts:116

  }

  @Mutation(() => ID, {
    description: 'mention user in a doc',
  })
  async mentionUser(
    @CurrentUser() me: UserType,
    @Args('input') input: MentionInput
  ) {
    const parsedInput = MentionNotificationCreateSchema.parse({
      userId: input.userId,
      body: {
        workspaceId: input.workspaceId,
        doc: input.doc,
        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);

View on GitHub (pinned to 591f874dad)