{"record":{"id":"cdcb7a9925de7f2d","repo":"elsa-workflows/elsa-core","slug":"external-identity-links-require-a-resolved-tenant","errorCode":null,"errorMessage":"External identity links require a resolved tenant.","messagePattern":"External identity links require a resolved tenant\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication/Services/ExternalIdentityLinkManagementService.cs","lineNumber":252,"sourceCode":"    {\n        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))\n            throw new ArgumentException(\"The issuer must be an absolute HTTPS URI without a query or fragment.\", nameof(issuer));\n        return uri.GetComponents(UriComponents.AbsoluteUri, UriFormat.UriEscaped).TrimEnd('/');\n    }\n\n    private static string NormalizeSubject(string subject)\n    {\n        var normalized = subject?.Trim();\n        if (string.IsNullOrEmpty(normalized) || normalized.Length > 4096)\n            throw new ArgumentException(\"The subject is required and must not exceed 4096 characters.\", nameof(subject));\n        return normalized;\n    }\n\n    private static void ValidateTargetTenant(string tenantId)\n    {\n        ArgumentNullException.ThrowIfNull(tenantId);\n        if (string.Equals(tenantId, ConnectionScope.HostTenantId, StringComparison.Ordinal))\n            throw new ArgumentException(\"External identity links require a resolved tenant.\", nameof(tenantId));\n    }\n}\n\npublic sealed record ExternalIdentityLinkUser(string Id, string DisplayName);\n\npublic abstract record ExternalIdentityLinkPrelinkResult\n{\n    private ExternalIdentityLinkPrelinkResult() { }\n    public sealed record Success(ExternalIdentityLink Link, bool WasCreated) : ExternalIdentityLinkPrelinkResult;\n    public sealed record Conflict(ExternalIdentityLink Link) : ExternalIdentityLinkPrelinkResult;\n    public sealed record UserNotFound : ExternalIdentityLinkPrelinkResult;\n    public sealed record ConnectionNotFound : ExternalIdentityLinkPrelinkResult;\n}\n","sourceCodeStart":234,"sourceCodeEnd":266,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication/Services/ExternalIdentityLinkManagementService.cs#L234-L266","documentation":"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.","triggerScenarios":"Thrown at src/modules/Elsa.ExternalAuthentication/Services/ExternalIdentityLinkManagementService.cs:252 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}