toeverything/AFFiNE · error · ActionForbidden

action_forbidden

action_forbidden

Error message

This feature is temporarily unavailable for you.

What it means

Thrown by WorkspaceMemberResolver.assertCanInviteOrShare when the acting user has been quarantined or banned by AFFiNE's invite-abuse detection system (runtime.isInviteAbuseUserQuarantinedOrBanned). It guards invite-link creation and share actions against accounts flagged for abusive invite behavior. The generic 'temporarily unavailable' message is intentional: it does not disclose that an abuse filter fired. Code action_forbidden, HTTP 403.

Solutions

  1. Stop retrying — the block is server-side state tied to the account, not a transient failure.
  2. Contact the workspace/server administrator or AFFiNE support to review and lift the quarantine on the account.
  3. Use a different, non-flagged account for legitimate invite needs while the review is pending.
  4. If you operate the server, inspect the invite-abuse quarantine state for the user via the runtime abuse controls and clear it if the flag was a false positive.
Defensive patterns

Strategy: try-catch

Type guard

function isActionForbiddenTemporarilyUnavailable(e: unknown): boolean {
  const ext = (e as { extensions?: Record<string, unknown> })?.extensions;
  return ext?.type === 'ACTION_FORBIDDEN' &&
    String(ext?.message ?? '').includes('temporarily unavailable');
}

Try / catch

try {
  const link = await createInviteLink(workspaceId, expireTime);
} catch (e) {
  if (isActionForbiddenTemporarilyUnavailable(e)) {
    // account quarantined/banned by invite-abuse system — surface 'contact support', do NOT retry
    return showContactSupportState();
  }
  throw e;
}

Prevention

When it happens

Trigger: A user flagged by the invite-abuse system calls createInviteLink (or any share/invite action routed through assertCanInviteOrShare). The user-level check runs before the workspace-level one, so the flagged actor is blocked on every workspace they touch.

Common situations: A user sent many invites in a short window and tripped the abuse detector; a shared/test account was previously quarantined; spam-like invite patterns from automated scripts reusing one account.

Related errors


AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18). Data as JSON: /api/errors/e95baad57277a627. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/core/workspaces/resolvers/member.ts:119

      throw new ActionForbidden(
        'Workspace names containing links or domains cannot be used to invite members.'
      );
    }
  }

  @ResolveField(() => UserType, {
    description: 'Owner of workspace',
    complexity: 2,
  })
  async owner(@Parent() workspace: WorkspaceType) {
    return this.models.workspaceUser.getOwner(workspace.id);
  }

  @ResolveField(() => Int, {
    description: 'member count of workspace',
    complexity: 2,
  })
  memberCount(@Parent() workspace: WorkspaceType) {
    return this.models.workspaceUser.count(workspace.id);
  }

  @ResolveField(() => [InviteUserType], {
    description: 'Members of workspace',
    complexity: 2,
  })
  async members(
    @CurrentUser() user: CurrentUser,
    @Parent() workspace: WorkspaceType,
    @Args('skip', { type: () => Int, nullable: true }) skip?: number,
    @Args('take', { type: () => Int, nullable: true }) take?: number,
    @Args('query', { type: () => String, nullable: true }) query?: string
  ) {
    await this.ac
      .user(user.id)
      .workspace(workspace.id)
      .assert('Workspace.Users.Read');

View on GitHub (pinned to 2af30773ae)