fullstackhero/dotnet-starter-kit · error · NotFoundException
impersonation grant not found
Error message
impersonation grant not found
What it means
RevokeAsync in ImpersonationGrantService throws NotFoundException when no ImpersonationGrants row matches the supplied id. The lookup is tenant-scoped via the DbContext; a nonexistent or already-purged grant id produces this error.
Solutions
- Verify the grant id exists (query ImpersonationGrants by id) before revoking
- Confirm you are pointed at the correct environment/database
- Re-fetch the grants list — the grant may have been purged
- Handle NotFoundException in the client and surface 'grant not found' to the user
Example fix
var grant = await db.ImpersonationGrants.FirstOrDefaultAsync(g => g.Id == id, ct);
if (grant is null) return Results.NotFound($"grant {id} not found");
await service.RevokeAsync(id, userId, ct); Defensive patterns
Strategy: try-catch
Validate before calling
var exists = await db.ImpersonationGrants.AnyAsync(g => g.Id == grantId, ct);
if (!exists) return Results.NotFound($"grant {grantId} not found"); Type guard
bool IsValidGrant(object? grant) => grant is ImpersonationGrant { Id: not Guid.Empty }; Try / catch
try
{
await impersonationService.RevokeAsync(grantId, adminUserId, ct);
}
catch (NotFoundException)
{
return Results.NotFound("impersonation grant not found");
} Prevention
- Fetch grants immediately before revoking instead of caching ids
- Confirm environment/connection string before operating on grant ids
- Handle NotFoundException as an expected outcome in revocation UIs
When it happens
Trigger: Calling RevokeAsync(id, revokedByUserId, ...) with an id that does not exist in the ImpersonationGrants table (typo, wrong environment/DB, or grant deleted by cleanup).
Common situations: Client cached a stale grant id after data re-seed; calling revoke against the wrong database/environment; grant purged by a retention job between listing and revoking.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Group with ID ' ' not found.
- Roles not found
- original actor not found
- impersonation grant not found
- target user not found
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/188da5044f1fd995.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Services/ImpersonationGrantService.cs:85
await db.SaveChangesAsync(ct).ConfigureAwait(false);
await SetCachedStatusAsync(grant, GrantState.EndedOrRevoked, ct).ConfigureAwait(false);
return ToDto(grant);
}
public async Task<ImpersonationGrantDto> RevokeAsync(
Guid id,
string revokedByUserId,
string? revokedByUserName,
string? reason,
CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNullOrWhiteSpace(revokedByUserId);
var grant = await db.ImpersonationGrants
.FirstOrDefaultAsync(g => g.Id == id, ct)
.ConfigureAwait(false)
?? throw new NotFoundException("impersonation grant not found");
if (grant.IsTerminal)
{
// Idempotent — surface the existing terminal state to the caller.
return ToDto(grant);
}
grant.Revoke(
revokedAtUtc: timeProvider.GetUtcNow().UtcDateTime,
revokedByUserId: revokedByUserId,
revokedByUserName: revokedByUserName,
reason: reason);
await db.SaveChangesAsync(ct).ConfigureAwait(false);
// Write the revocation marker BEFORE returning so a racing request
// doesn't slip through with a cached Active marker.
await SetCachedStatusAsync(grant, GrantState.EndedOrRevoked, ct).ConfigureAwait(false);
View on GitHub (pinned to 3f2959e683)