fullstackhero/dotnet-starter-kit · error · ForbiddenException

Channel admin role required.

Error message

Channel admin role required.

What it means

ChannelAuthorization.RequireAdmin throws ForbiddenException("Channel admin role required.") when the user is a member of the channel but their ChannelMemberRole is not Admin. It is raised after RequireMember succeeds, so the user is authenticated and a member — just not privileged enough. Maps to HTTP 403.

Solutions

  1. Have an existing channel Admin promote the user: set their ChannelMemberRole to Admin.
  2. Hide/disable admin-only UI actions unless the current member's role is Admin.
  3. Confirm the membership role loaded in the handler is current (stale cache may hold an old role).
  4. If the operation should be member-wide, relax the handler to RequireMember instead — only with product approval.

Example fix

// before
channel.RequireAdmin(userId); // throws for plain members

// after
var member = channel.Members.First(m => m.UserId == userId);
if (member.Role != ChannelMemberRole.Admin)
{
    member.Role = ChannelMemberRole.Admin; // promoted by an existing admin beforehand
}
channel.RequireAdmin(userId);
Defensive patterns

Strategy: type-guard

Validate before calling

const me = channel.members.find(m => m.userId === currentUserId);
if (!me || me.role !== "admin") {
  // hide admin actions / show "admin required" notice
  return;
}

Type guard

function isAdminMember(m: { userId: string; role: string } | undefined, userId: string): m is { userId: string; role: "admin" } {
  return !!m && m.userId === userId && m.role === "admin";
}

Try / catch

try {
  await api.updateChannel({ channelId, name });
} catch (e) {
  if (e.status === 403) { notify("Channel admin role required."); }
  else throw e;
}

Prevention

When it happens

Trigger: UpdateChannelCommandHandler calls channel.RequireAdmin(userId); a plain Member (or Owner with non-admin role) attempts to rename a channel, change its description, or toggle IsPrivate.

Common situations: A regular member trying to rename a channel in the UI where the button was wrongly enabled; role demoted from Admin to Member after the client cached stale permissions; frontend not checking the member role before offering admin actions.

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 fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/f56657a0e3054ef3. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Chat/Modules.Chat/Features/v1/Internal/ChannelAuthorization.cs:25

/// <summary>
/// Small assertion helpers used by channel/message handlers so the rules stay in one place.
/// Throws framework-aware exceptions so the global handler emits the right HTTP status.
/// </summary>
internal static class ChannelAuthorization
{
    public static ChannelMember RequireMember(this ChatChannel channel, string userId)
    {
        var member = channel.Members.FirstOrDefault(m => string.Equals(m.UserId, userId, StringComparison.Ordinal));
        // Use NotFoundException (404) instead of Forbidden so non-members can't probe channel existence.
        return member ?? throw new NotFoundException("Channel not found.");
    }

    public static ChannelMember RequireAdmin(this ChatChannel channel, string userId)
    {
        var member = channel.RequireMember(userId);
        if (member.Role != ChannelMemberRole.Admin)
        {
            throw new ForbiddenException("Channel admin role required.");
        }
        return member;
    }
}

View on GitHub (pinned to 3f2959e683)