{"record":{"id":"8e419e867e2bc8f4","repo":"fullstackhero/dotnet-starter-kit","slug":"theme-for-tenant-tenantid-not-found","errorCode":null,"errorMessage":"Theme for tenant {tenantId} not found","messagePattern":"Theme for tenant (.+?) not found","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Multitenancy/Modules.Multitenancy/Services/TenantThemeService.cs","lineNumber":243,"sourceCode":"\n        // Clear existing default\n        var existingDefault = await _dbContext.TenantThemes\n            .FirstOrDefaultAsync(t => t.IsDefault, ct)\n            .ConfigureAwait(false);\n\n        if (existingDefault is not null)\n        {\n            existingDefault.IsDefault = false;\n        }\n\n        // Set new default\n        var entity = await _dbContext.TenantThemes\n            .FirstOrDefaultAsync(t => t.TenantId == tenantId, ct)\n            .ConfigureAwait(false);\n\n        if (entity is null)\n        {\n            throw new NotFoundException($\"Theme for tenant {tenantId} not found\");\n        }\n\n        entity.IsDefault = true;\n        await _dbContext.SaveChangesAsync(ct).ConfigureAwait(false);\n\n        // Invalidate default theme cache\n        await _cache.RemoveAsync(CacheKeys.DefaultTheme, ct).ConfigureAwait(false);\n\n        if (_logger.IsEnabled(LogLevel.Information))\n        {\n            _logger.LogInformation(\"Set theme for tenant {TenantId} as default\", tenantId);\n        }\n    }\n\n    public async Task InvalidateCacheAsync(string tenantId, CancellationToken ct = default)\n    {\n        // Purge both the tenant-specific entry and anything tagged for this tenant.\n        await _cache.RemoveAsync(CacheKeys.TenantTheme(tenantId), ct).ConfigureAwait(false);","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Multitenancy/Modules.Multitenancy/Services/TenantThemeService.cs#L225-L261","documentation":"TenantThemeService.SetAsDefaultThemeAsync looks up the TenantTheme row for the given tenantId and throws NotFoundException when no theme record exists for that tenant. Themes must be created before one can be promoted to default; the service refuses to implicitly create one. The exception maps to an HTTP 404 for the caller.","triggerScenarios":"Calling SetAsDefaultThemeAsync(tenantId) (or the SetDefaultTheme endpoint) when the tenant has no row in the TenantThemes table — i.e. no theme was ever created/seeded for that tenant, or the theme row was deleted.","commonSituations":"Running against a fresh database where the theme seeder did not run; calling the set-default endpoint before the tenant customized a theme; using a tenantId from another environment (staging vs prod) where the theme record is missing; a manual cleanup deleted the TenantTheme row.","solutions":["Run the theme seeding/migration (dotnet run --project src/Host/FSH.Starter.DbMigrator -- apply --seed) so the tenant gets a TenantTheme row.","Create a theme for the tenant first (CreateTheme endpoint/handler), then call SetAsDefaultThemeAsync.","Verify the tenantId is correct and matches the tenant that actually owns the theme row (watch out for cross-environment tenant IDs).","Check the TenantThemes table for the row: SELECT * FROM \"TenantThemes\" WHERE \"TenantId\" = '<tenantId>'."],"exampleFix":"// before\nawait tenantThemeService.SetAsDefaultThemeAsync(tenantId, ct); // throws if no theme exists\n// after\nvar theme = await tenantThemeService.GetThemeAsync(tenantId, ct);\nif (theme is null)\n{\n    await tenantThemeService.CreateDefaultThemeAsync(tenantId, ct); // ensure a theme exists\n}\nawait tenantThemeService.SetAsDefaultThemeAsync(tenantId, ct);","handlingStrategy":"try-catch","validationCode":"var theme = await tenantThemeService.GetThemeAsync(tenantId, ct);\nif (theme is null) throw new InvalidOperationException($\"No theme exists for tenant {tenantId}; create one before setting default.\");","typeGuard":"bool HasTheme(ThemeDto? theme) => theme is not null && !string.IsNullOrWhiteSpace(theme.TenantId);","tryCatchPattern":"try\n{\n    await tenantThemeService.SetAsDefaultThemeAsync(tenantId, ct);\n}\ncatch (NotFoundException)\n{\n    logger.LogWarning(\"No theme found for tenant {TenantId}; creating one first.\", tenantId);\n    await tenantThemeService.CreateDefaultThemeAsync(tenantId, ct);\n    await tenantThemeService.SetAsDefaultThemeAsync(tenantId, ct);\n}","preventionTips":["Always create/seed a TenantTheme row as part of tenant provisioning.","Fetch the theme before promoting it to default.","Validate tenantId against the environment you are targeting.","Catch NotFoundException at the endpoint layer and map it to a helpful 404 message."],"tags":["multitenancy","not-found","theme"],"backgroundTag":"entity-not-found","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"}