fullstackhero/dotnet-starter-kit · error · UnauthorizedException
Invalid tenant
Error message
Invalid tenant
What it means
SessionService.EnsureValidTenant guards every session operation: if the Finbuckle multitenant context has no resolved TenantInfo.Id (blank/missing tenant), it throws UnauthorizedException('Invalid tenant'). Sessions are tenant-scoped, so no session work can proceed without a resolved tenant.
Solutions
- Send the tenant identifier on every request (e.g. X-Tenant header or __tenant__ route/query as configured in MultitenancyModule)
- Verify the tenant id exists and matches a registered tenant
- Check middleware ordering so Finbuckle multitenancy middleware runs before auth/endpoint resolution
- In tests, initialize the IMultiTenantContextAccessor with a valid TenantInfo before calling the service
Example fix
// before
client.DefaultRequestHeaders.Add("Accept", "application/json");
// after
client.DefaultRequestHeaders.Add("X-Tenant", "tenant-xyz");
client.DefaultRequestHeaders.Add("Accept", "application/json"); Defensive patterns
Strategy: validation
Validate before calling
var tenantId = httpContextAccessor.HttpContext?.GetMultiTenantContext<TenantInfo>()?.TenantInfo?.Id;
if (string.IsNullOrWhiteSpace(tenantId))
return Results.Problem(statusCode: 401, detail: "Tenant could not be resolved — supply a valid tenant identifier."); Type guard
bool HasResolvedTenant(IMultiTenantContextAccessor? a) =>
!string.IsNullOrWhiteSpace(a?.MultiTenantContext?.TenantInfo?.Id); Try / catch
try
{
await sessionService.GetUserSessionsAsync(userId, ct);
}
catch (UnauthorizedException ex) when (ex.Message == "Invalid tenant")
{
return Results.Problem(statusCode: 401, detail: "Tenant could not be resolved — supply a valid tenant identifier.");
} Prevention
- Always send the tenant identifier header/route value on API calls
- Verify Finbuckle middleware ordering in the host pipeline
- Document the tenant resolution strategy (header vs route vs claim) for API consumers
- In integration tests, seed the multitenant context before calling session services
When it happens
Trigger: Any SessionService call (CreateSessionAsync, GetUserSessionsAsync, GetTenantSessionsAsync, GetSessionAsync, RevokeSessionAsync, RevokeAllSessionsAsync, GetUserSessionsForAdminAsync) executed on a request where the __tenant__ identifier is absent or does not resolve to a known tenant.
Common situations: Client omitted the tenant header/claim; tenant identifier string misspelled; middleware order issue where multitenancy middleware didn't run; direct service invocation in tests without setting up MultiTenantContext.
Related errors
- missing tenant context
- missing tenant context
- Unauthorized
- tenant is deactivated
- tenant validity has expired
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/7ef60c820a87eb91.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Services/SessionService.cs:43
IdentityDbContext db,
ICurrentUser currentUser,
IMultiTenantContextAccessor<AppTenantInfo> multiTenantContextAccessor,
ILogger<SessionService> logger,
TimeProvider timeProvider)
{
_db = db;
_currentUser = currentUser;
_multiTenantContextAccessor = multiTenantContextAccessor;
_logger = logger;
_timeProvider = timeProvider;
_uaParser = Parser.GetDefault();
}
private void EnsureValidTenant()
{
if (string.IsNullOrWhiteSpace(_multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id))
{
throw new UnauthorizedException("Invalid tenant");
}
}
public async Task<UserSessionDto> CreateSessionAsync(
string userId,
string refreshTokenHash,
string ipAddress,
string userAgent,
DateTime expiresAt,
CancellationToken cancellationToken = default)
{
EnsureValidTenant();
var clientInfo = _uaParser.Parse(userAgent);
var session = UserSession.Create(
userId: userId,
refreshTokenHash: refreshTokenHash,View on GitHub (pinned to 3f2959e683)