fullstackhero/dotnet-starter-kit · error · NotFoundException

Tenant not found for provisioning.

Error message

Tenant {tenantId} not found for provisioning.

What it means

TenantProvisioningService.StartAsync throws NotFoundException ("Tenant {tenantId} not found for provisioning.") when asked to start a provisioning run for a tenant id that does not exist in the tenant store. This is the synchronous entry point before a run row is created; the job-side equivalent is TenantProvisioningJob.RunAsync. A subsequent guard also rejects starts while a run is already Pending/Running.

Solutions

  1. Confirm the tenantId exists (GET the tenant) before starting provisioning.
  2. Recreate the tenant if it was deleted and provisioning is needed.
  3. Refresh the admin UI's tenant list to drop stale entries.
  4. Fix the request payload if the id was mistyped or truncated.

Example fix

// before
await provisioningService.StartAsync("acme-mispelled", ct);
// after
var tenant = await tenantStore.GetAsync("acme", ct) ?? throw new NotFoundException("Tenant acme missing");
await provisioningService.StartAsync(tenant.Id, ct);
Defensive patterns

Strategy: validation

Validate before calling

var tenant = await tenantStore.GetAsync(tenantId, ct);
if (tenant is null) return Result.NotFound($"Tenant {tenantId} does not exist.");

Try / catch

try { await provisioningService.StartAsync(tenantId, ct); }
catch (NotFoundException) { refreshTenantList(); showError("Tenant not found — it may have been deleted."); }

Prevention

When it happens

Trigger: Calling the provisioning start API/endpoint with an unknown or deleted tenantId; a client racing tenant deletion with a provisioning request; a typo'd or truncated tenant id in the request.

Common situations: Admin UI caching a tenant list while the tenant was deleted elsewhere; retrying a failed request after the tenant was removed; integration tests hitting a cleaned database.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningService.cs:39

    public TenantProvisioningService(
        TenantDbContext dbContext,
        IMultiTenantStore<AppTenantInfo> tenantStore,
        IJobService jobService,
        IServiceScopeFactory scopeFactory,
        ILogger<TenantProvisioningService> logger)
    {
        _dbContext = dbContext;
        _tenantStore = tenantStore;
        _jobService = jobService;
        _scopeFactory = scopeFactory;
        _logger = logger;
    }

    public async Task<TenantProvisioning> StartAsync(string tenantId, CancellationToken cancellationToken)
    {
        var tenant = await _tenantStore.GetAsync(tenantId).ConfigureAwait(false)
            ?? throw new NotFoundException($"Tenant {tenantId} not found for provisioning.");

        var existing = await GetLatestAsync(tenantId, cancellationToken).ConfigureAwait(false);
        if (existing is not null && (existing.Status is TenantProvisioningStatus.Running or TenantProvisioningStatus.Pending))
        {
            throw new CustomException($"Provisioning already running for tenant {tenantId}.");
        }

        var correlationId = Guid.NewGuid().ToString();
        var provisioning = new TenantProvisioning(tenant.Id, correlationId);

        provisioning.Steps.Add(new TenantProvisioningStep(provisioning.Id, TenantProvisioningStepName.Database));
        provisioning.Steps.Add(new TenantProvisioningStep(provisioning.Id, TenantProvisioningStepName.Migrations));
        provisioning.Steps.Add(new TenantProvisioningStep(provisioning.Id, TenantProvisioningStepName.Seeding));
        provisioning.Steps.Add(new TenantProvisioningStep(provisioning.Id, TenantProvisioningStepName.CacheWarm));

        _dbContext.Add(provisioning);
        await _dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

View on GitHub (pinned to 3f2959e683)