fullstackhero/dotnet-starter-kit · error · NotFoundException

Role store not configured. Ensure .AddRoles

Error message

Role store not configured. Ensure .AddRoles<FshRole>() and EF stores.

What it means

RoleService.GetRolesAsync checks that roleManager.Roles (the IQueryable from the role store) is not null. A null queryable means Identity was registered without a role store (no .AddRoles<FshRole>() with EF stores backing it), so the service throws NotFoundException('Role store not configured. Ensure .AddRoles<FshRole>() and EF stores.').

Solutions

  1. Ensure the IdentityBuilder chain includes .AddRoles<FshRole>() before .AddEntityFrameworkStores<TContext>()
  2. Verify the EF identity stores are registered with the module's DbContext
  3. Check for custom RoleManager/store registrations that may shadow the EF store

Example fix

// before
services.AddIdentity<FshUser, FshRole>()
    .AddEntityFrameworkStores<IdentityDbContext>();
// after
services.AddIdentity<FshUser, FshRole>()
    .AddRoles<FshRole>()
    .AddEntityFrameworkStores<IdentityDbContext>();
Defensive patterns

Strategy: validation

Validate before calling

// startup check
using var scope = app.Services.CreateScope();
var rm = scope.ServiceProvider.GetRequiredService<RoleManager<FshRole>>();
if (rm.Roles is null) throw new InvalidOperationException('Role store missing: add .AddRoles<FshRole>() with EF stores');

Type guard

bool RoleStoreConfigured(RoleManager<FshRole>? rm) => rm?.Roles is not null;

Try / catch

try { var roles = await roleService.GetRolesAsync(1, 20); }
catch (Exception e) when (e.Message.Contains("Role store not configured")) { logger.LogError(e, "Identity role store misconfigured"); throw; }

Prevention

When it happens

Trigger: Calling the roles list endpoint on an Identity registration that omitted AddRoles<FshRole>() or the EF role store, causing RoleManager.Roles to be null.

Common situations: Trimmed-down Identity setup copied from a minimal sample (users only, no roles); swapping to a custom role store that returns null Roles; a module registration refactor that dropped AddRoles from the IdentityBuilder chain.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/4928334e3142fbd9. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs:63

            .ToListAsync(cancellationToken);

        foreach (var userId in directUserIds.Concat(groupUserIds).Distinct())
        {
            await userPermissionService.InvalidatePermissionCacheAsync(userId, cancellationToken).ConfigureAwait(false);
        }
    }

    public async Task<PagedResponse<RoleDto>> GetRolesAsync(
        int pageNumber = 1,
        int pageSize = 20,
        string? search = null,
        CancellationToken cancellationToken = default)
    {
        if (roleManager is null)
            throw new NotFoundException("RoleManager<FshRole> not resolved. Check Identity registration.");

        if (roleManager.Roles is null)
            throw new NotFoundException("Role store not configured. Ensure .AddRoles<FshRole>() and EF stores.");

        var page = Math.Max(1, pageNumber);
        var size = Math.Clamp(pageSize, 1, 200);

        var query = roleManager.Roles.AsNoTracking();
        if (!string.IsNullOrWhiteSpace(search))
        {
            var needle = search.Trim().ToLowerInvariant();
            query = query.Where(r =>
                (r.Name != null && r.Name.ToLower().Contains(needle))
                || (r.Description != null && r.Description.ToLower().Contains(needle)));
        }

        var total = await query.LongCountAsync(cancellationToken).ConfigureAwait(false);
        var rows = await query
            .OrderBy(r => r.Name)
            .Skip((page - 1) * size)
            .Take(size)

View on GitHub (pinned to 3f2959e683)