fullstackhero/dotnet-starter-kit · warning · CustomException
cannot impersonate yourself
Error message
cannot impersonate yourself
What it means
Self-impersonation (same user id and same tenant) is rejected with CustomException('cannot impersonate yourself', BadRequest) — an explicit 4xx rather than the 500 CustomException defaults to. It is pointless and would pollute the audit trail.
Solutions
- Pass a different TargetUserId (the user to impersonate)
- Fix the UI/form so the target user cannot default to the signed-in user
- Adjust tests to use two distinct users
Example fix
// before const targetUserId = currentUser.id; // wrong: self // after const targetUserId = selectedUser.id; // a different user in the same tenant
Defensive patterns
Strategy: validation
Validate before calling
if (targetUserId === currentUserId && targetTenantId === currentTenantId) {
throw new Error('cannot impersonate yourself: pick a different target user');
} Try / catch
try { await api.startImpersonation(req); }
catch (e) { if (e.status === 400 && /yourself/.test(e.message)) { notify('Select a different user to impersonate'); return; } throw e; } Prevention
- Disable the current user in target-user pickers
- Use distinct actor/target fixtures in tests
- Never default the target to the signed-in user
When it happens
Trigger: Calling start-impersonation with TargetUserId equal to the caller's own user id and TargetTenantId equal to the caller's tenant.
Common situations: A support UI pre-filling the 'current user' as the target by accident; automated tests using the same fixture user for actor and target; copying your own user id from the profile page into the request.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A category cannot be its own parent.
- Unknown visibility value
- current session is not an impersonation session
- end current impersonation before starting a new one
- File exceeds max size of
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/66fd162dd32ce492.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Features/v1/Impersonation/StartImpersonation/StartImpersonationCommandHandler.cs:77
var actorUserId = _currentUser.GetUserId().ToString();
var actorTenantId = _currentUser.GetTenant()
?? throw new UnauthorizedException("missing tenant context");
var actorUserName = _currentUser.Name;
// Cross-tenant impersonation requires the actor to be in the root tenant. Tenant admins
// can only impersonate users within their own tenant.
if (!string.Equals(actorTenantId, MultitenancyConstants.Root.Id, StringComparison.Ordinal)
&& !string.Equals(actorTenantId, request.TargetTenantId, StringComparison.Ordinal))
{
throw new ForbiddenException("cross-tenant impersonation is restricted to platform operators");
}
// Prevent self-impersonation (pointless, confuses the audit trail). Caller error → explicit 4xx,
// not the 500 CustomException defaults to.
if (string.Equals(actorUserId, request.TargetUserId, StringComparison.Ordinal)
&& string.Equals(actorTenantId, request.TargetTenantId, StringComparison.Ordinal))
{
throw new CustomException("cannot impersonate yourself", errors: null, System.Net.HttpStatusCode.BadRequest);
}
// Prevent nesting: if the caller is already impersonating, require end-impersonation first.
var callerClaims = _currentUser.GetUserClaims();
if (callerClaims is not null
&& callerClaims.Any(c => c.Type == ClaimConstants.ActorSubject))
{
throw new CustomException(
"end current impersonation before starting a new one",
errors: null,
System.Net.HttpStatusCode.BadRequest);
}
var targetClaimsResult = await _identityService
.BuildClaimsForUserAsync(request.TargetUserId, request.TargetTenantId, cancellationToken);
if (targetClaimsResult is null)
{View on GitHub (pinned to 3f2959e683)