{"record":{"id":"c8d6d42b46777588","repo":"fullstackhero/dotnet-starter-kit","slug":"tenant-tenantid-not-found-during-provisioning","errorCode":null,"errorMessage":"Tenant {tenantId} not found during provisioning.","messagePattern":"Tenant (.+?) not found during provisioning\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningJob.cs","lineNumber":37,"sourceCode":"\n    public TenantProvisioningJob(\n        ITenantProvisioningService provisioningService,\n        IMultiTenantStore<AppTenantInfo> tenantStore,\n        IMultiTenantContextSetter tenantContextSetter,\n        ITenantService tenantService,\n        ILogger<TenantProvisioningJob> logger)\n    {\n        _provisioningService = provisioningService;\n        _tenantStore = tenantStore;\n        _tenantContextSetter = tenantContextSetter;\n        _tenantService = tenantService;\n        _logger = logger;\n    }\n\n    public async Task RunAsync(string tenantId, string correlationId, CancellationToken cancellationToken = default)\n    {\n        var tenant = await _tenantStore.GetAsync(tenantId).ConfigureAwait(false)\n            ?? throw new NotFoundException($\"Tenant {tenantId} not found during provisioning.\");\n\n        var currentStep = TenantProvisioningStepName.Database;\n        try\n        {\n            var runDatabase = await _provisioningService.MarkRunningAsync(tenantId, correlationId, currentStep, cancellationToken).ConfigureAwait(false);\n\n            _tenantContextSetter.MultiTenantContext = new MultiTenantContext<AppTenantInfo>(tenant);\n\n            if (runDatabase)\n            {\n                await _provisioningService.MarkStepCompletedAsync(tenantId, correlationId, currentStep, cancellationToken).ConfigureAwait(false);\n            }\n\n            currentStep = TenantProvisioningStepName.Migrations;\n            var runMigrations = await _provisioningService.MarkRunningAsync(tenantId, correlationId, currentStep, cancellationToken).ConfigureAwait(false);\n            if (runMigrations)\n            {\n                await _tenantService.MigrateTenantAsync(tenant, cancellationToken).ConfigureAwait(false);","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningJob.cs#L19-L55","documentation":"TenantProvisioningJob.RunAsync throws NotFoundException (\"Tenant {tenantId} not found during provisioning.\") when the background job starts but the tenant row no longer exists in the tenant store. The provisioning run cannot proceed without the tenant record.","triggerScenarios":"Enqueueing provisioning for a tenant id that was deleted between enqueue and job execution; a Hangfire retry firing after tenant cleanup; passing a wrong/typo'd tenant id when scheduling the job.","commonSituations":"Hangfire retries firing after the tenant was removed in a rollback; tests or scripts enqueueing provisioning for fabricated ids; tenant deletion racing with queued provisioning.","solutions":["Verify the tenantId exists in the tenant store before enqueueing the job.","If the tenant was deleted intentionally, cancel/remove the queued job and its retries.","Recreate the tenant and re-trigger provisioning if it should exist.","Check job arguments/logs for a corrupted or truncated tenant id."],"exampleFix":"// before\nawait backgroundJobClient.EnqueueAsync<TenantProvisioningJob>(j => j.RunAsync(tenantId, corrId, ct));\n// after\nif (await _tenantStore.GetAsync(tenantId) is null)\n    throw new ValidationException($\"Cannot provision: tenant {tenantId} does not exist.\");\nawait backgroundJobClient.EnqueueAsync<TenantProvisioningJob>(j => j.RunAsync(tenantId, corrId, ct));","handlingStrategy":"validation","validationCode":"var tenant = await tenantStore.GetAsync(tenantId);\nif (tenant is null) throw new ValidationException($\"Tenant {tenantId} missing; not enqueueing provisioning.\");","typeGuard":null,"tryCatchPattern":"try { await job.RunAsync(tenantId, corrId); }\ncatch (NotFoundException) { logger.LogWarning(\"Skipping provisioning; tenant {TenantId} gone\", tenantId); }","preventionTips":["Delete queued provisioning jobs when deleting a tenant.","Validate tenant existence at enqueue time, not only inside the job.","Limit Hangfire retry counts for jobs that depend on ephemeral rows.","Log correlationId to trace the enqueue-to-run gap."],"tags":["multitenancy","provisioning","background-jobs","not-found"],"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"}