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
- Have an existing channel Admin promote the user: set their ChannelMemberRole to Admin.
- Hide/disable admin-only UI actions unless the current member's role is Admin.
- Confirm the membership role loaded in the handler is current (stale cache may hold an old role).
- 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
- Gate admin UI actions on the member role, not just membership.
- Re-fetch role after any demotion event.
- Don't cache roles longer than the channel membership query.
- Promote users via an admin before assigning them admin workflows.
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
- Only the author can edit a message.
- Only the author or a moderator can delete.
- Only channel admins can add members to private channels.
- Channel not found.
- not allowed to change this file's visibility
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)