elsa-workflows/elsa-core · error · InvalidOperationException
The unlinked identity policy
Error message
The unlinked identity policy '{selection.Type}' is not available. What it means
Thrown by DefaultExternalIdentityResolver.ResolveAsync when the connection's configured unlinked-identity policy selection references a policy Type that is not present in the dictionary of IUnlinkedIdentityPolicy implementations resolved from DI. It is a configuration guard: the connection was set up with a policy type no registered provider implements.
Solutions
- Register the missing IUnlinkedIdentityPolicy implementation (matching selection.Type) in the DI container.
- Update the connection configuration to select a policy type that is registered.
- Check for typos or casing mismatches between the configured policy type string and the registered policy's Type value.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src/modules/Elsa.ExternalAuthentication/Services/DefaultExternalIdentityResolver.cs:32 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/9f9b566c5956ad20.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.ExternalAuthentication/Services/DefaultExternalIdentityResolver.cs:32
IOptions<ExternalAuthenticationOptions> options) : IExternalIdentityResolver, IExternalIdentitySignInTracker
{
private readonly IReadOnlyDictionary<string, IUnlinkedIdentityPolicy> _policies = policies.ToDictionary(x => x.Type, StringComparer.Ordinal);
public async ValueTask<ExternalIdentityResolution> ResolveAsync(ExternalIdentityResolutionContext context, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(context);
var connectionKey = ConnectionRevisionCalculator.NormalizeKey(context.Connection.Connection.Key);
var existingLink = await provisioner.FindLinkAsync(context.TargetTenantId, connectionKey, context.Identity, cancellationToken);
if (existingLink is not null)
{
ValidateLink(existingLink, context);
return new(existingLink.UserId, false);
}
var selection = GetPolicySelection(context.Connection);
var policy = _policies.GetValueOrDefault(selection.Type)
?? throw new InvalidOperationException($"The unlinked identity policy '{selection.Type}' is not available.");
var decision = await policy.EvaluateAsync(new(
context.TargetTenantId,
context.Connection,
context.Identity,
context.ProjectedClaims,
selection.Settings), cancellationToken);
var result = decision switch
{
UnlinkedIdentityDecision.Reject reject => throw new ExternalIdentityUnlinkedException(reject.SafeReason),
UnlinkedIdentityDecision.CreateUser createUser => await provisioner.CreateLinkOrGetExistingAsync(
new(context.TargetTenantId, connectionKey, context.Identity, createUser.Proposal), cancellationToken),
UnlinkedIdentityDecision.LinkExistingUser linkExistingUser => await provisioner.CreateLinkOrGetExistingAsync(
new(context.TargetTenantId, connectionKey, context.Identity, null, linkExistingUser.UserId), cancellationToken),
_ => throw new InvalidOperationException("The unlinked identity policy returned an unsupported decision.")
};
ValidateLink(result.Link, context);View on GitHub (pinned to fe9217bdfa)