{"record":{"id":"3c24254ad2d3eecd","repo":"fullstackhero/dotnet-starter-kit","slug":"invalid-tenant-userstatusservice","errorCode":null,"errorMessage":"invalid tenant","messagePattern":"invalid tenant","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs","lineNumber":43,"sourceCode":"\n    public async Task ToggleStatusAsync(bool activateUser, string userId, CancellationToken cancellationToken)\n    {\n        EnsureValidTenant();\n\n        var context = await BuildToggleContextAsync(userId, activateUser, cancellationToken);\n\n        await ValidateTogglePermissionsAsync(context, cancellationToken);\n\n        ApplyStatusChange(context);\n\n        await SaveAndAuditAsync(context, cancellationToken);\n    }\n\n    private void EnsureValidTenant()\n    {\n        if (string.IsNullOrWhiteSpace(multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id))\n        {\n            throw new UnauthorizedException(\"invalid tenant\");\n        }\n    }\n\n    private async Task<ToggleStatusContext> BuildToggleContextAsync(\n        string userId,\n        bool activateUser,\n        CancellationToken cancellationToken)\n    {\n        var actorId = currentUser.GetUserId();\n        if (actorId == Guid.Empty)\n        {\n            throw new UnauthorizedException(\"authenticated user required to toggle status\");\n        }\n\n        var actor = await userManager.FindByIdAsync(actorId.ToString())\n            ?? throw new UnauthorizedException(\"current user not found\");\n\n        var targetUser = await userManager.Users","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs#L25-L61","documentation":"Thrown by UserStatusService.EnsureValidTenant when the Finbuckle multitenant context has no resolved tenant id for the current request. Session-related operations (create/list/revoke sessions, admin and tenant session queries) all require a tenant context to scope their queries.","triggerScenarios":"Any session endpoint hit without a tenant identifier header/segment, or with middleware configured so the tenant resolver cannot match the request (wrong host, missing __tenant__ form/query value).","commonSituations":"Calling the API directly without the tenant header that the frontend normally injects; misconfigured multitenancy strategy in the host; integration tests missing tenant setup; new custom domain not registered with the tenant resolver.","solutions":["Send the correct tenant identifier with the request (header/query/host per the configured Finbuckle strategy).","Check the multitenancy middleware/strategy registration in the API host.","Verify the tenant exists and its resolver mappings (host, identifier) are correct.","In tests, set up the tenant context before calling session services."],"exampleFix":"// before: request without tenant info -> 401 invalid tenant\nawait apiFetch(\"/api/v1/users/sessions\", { headers: {} });\n// after\nawait apiFetch(\"/api/v1/users/sessions\", { headers: { \"tenant\": \"root\" } });","handlingStrategy":"validation","validationCode":"const tenantId = resolveTenant(); // header/query/host per app config\nif (!tenantId) throw new Error(\"No tenant resolved — set the tenant header before calling session APIs\");","typeGuard":null,"tryCatchPattern":"try { await apiFetch(\"/api/v1/users/sessions\"); } catch (e) {\n  if (e.status === 401 && /invalid tenant/i.test(e.message)) { redirectTenantSelection(); return; }\n  throw e;\n}","preventionTips":["Configure the API client to always send the tenant identifier header.","Register custom hosts with the Finbuckle resolver strategy.","In integration tests, initialize the tenant context before service calls."],"tags":["multitenancy","authentication","finbuckle"],"backgroundTag":"authentication-required","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}