elsa-workflows/elsa-core · error · ArgumentException
External identity links require a resolved tenant.
Error message
External identity links require a resolved tenant.
What it means
A validation guard thrown by ValidateTargetTenant, which is invoked by every query and mutation of ExternalIdentityLinkManagementService (ListAsync, FindUsersAsync, PrelinkAsync, UnlinkAsync, ReplaceAsync). External identity links are tenant-scoped, so the ambient tenant context must be resolved to a concrete tenant; a null or unresolved tenant id makes the operation ambiguous and is rejected.
Solutions
- Run the operation within a resolved tenant context (e.g. via a tenant-scoped API route or ITenantAccessor set beforehand).
- Do not call link management endpoints from tenant-agnostic background work; iterate tenants explicitly.
- Check the tenant resolver pipeline if callers that should be tenant-scoped arrive unresolved.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src/modules/Elsa.ExternalAuthentication/Services/ExternalIdentityLinkManagementService.cs:252 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/cdcb7a9925de7f2d.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.ExternalAuthentication/Services/ExternalIdentityLinkManagementService.cs:252
{
if (!Uri.TryCreate(issuer?.Trim(), UriKind.Absolute, out var uri) || !string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrEmpty(uri.Query) || !string.IsNullOrEmpty(uri.Fragment))
throw new ArgumentException("The issuer must be an absolute HTTPS URI without a query or fragment.", nameof(issuer));
return uri.GetComponents(UriComponents.AbsoluteUri, UriFormat.UriEscaped).TrimEnd('/');
}
private static string NormalizeSubject(string subject)
{
var normalized = subject?.Trim();
if (string.IsNullOrEmpty(normalized) || normalized.Length > 4096)
throw new ArgumentException("The subject is required and must not exceed 4096 characters.", nameof(subject));
return normalized;
}
private static void ValidateTargetTenant(string tenantId)
{
ArgumentNullException.ThrowIfNull(tenantId);
if (string.Equals(tenantId, ConnectionScope.HostTenantId, StringComparison.Ordinal))
throw new ArgumentException("External identity links require a resolved tenant.", nameof(tenantId));
}
}
public sealed record ExternalIdentityLinkUser(string Id, string DisplayName);
public abstract record ExternalIdentityLinkPrelinkResult
{
private ExternalIdentityLinkPrelinkResult() { }
public sealed record Success(ExternalIdentityLink Link, bool WasCreated) : ExternalIdentityLinkPrelinkResult;
public sealed record Conflict(ExternalIdentityLink Link) : ExternalIdentityLinkPrelinkResult;
public sealed record UserNotFound : ExternalIdentityLinkPrelinkResult;
public sealed record ConnectionNotFound : ExternalIdentityLinkPrelinkResult;
}
View on GitHub (pinned to fe9217bdfa)