{"record":{"id":"1af89493d11c9aaf","repo":"elsa-workflows/elsa-core","slug":"openid-connect-settings-must-be-an-object","errorCode":null,"errorMessage":"OpenID Connect settings must be an object.","messagePattern":"OpenID Connect settings must be an object\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectSettingsV1Migration.cs","lineNumber":17,"sourceCode":"using System.Text.Json;\nusing System.Text.Json.Nodes;\nusing Elsa.ExternalAuthentication.Contracts;\n\nnamespace Elsa.ExternalAuthentication.OpenIdConnect.Services;\n\n/// <summary>Migrates the unreleased v1 authority/callback settings to the v2 deployment-derived callback model.</summary>\npublic sealed class OpenIdConnectSettingsV1Migration : IAdapterSettingsMigration\n{\n    public string AdapterType => OpenIdConnectExternalAuthenticationAdapter.AdapterType;\n    public int FromVersion => 1;\n    public int ToVersion => 2;\n\n    public ValueTask<JsonElement> MigrateAsync(JsonElement settings, CancellationToken cancellationToken = default)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        var node = JsonNode.Parse(settings.GetRawText())?.AsObject() ?? throw new InvalidOperationException(\"OpenID Connect settings must be an object.\");\n        if (!node.ContainsKey(\"discoveryUrl\") && node[\"authority\"]?.GetValue<string>() is { Length: > 0 } authority)\n            node[\"discoveryUrl\"] = authority.TrimEnd('/') + \"/.well-known/openid-configuration\";\n        node.Remove(\"authority\");\n        node.Remove(\"callbackUri\");\n        node[\"providerPkce\"] = \"required\";\n        node[\"clientAuthenticationMethod\"] ??= \"client_secret_basic\";\n        using var document = JsonDocument.Parse(node.ToJsonString());\n        return ValueTask.FromResult(document.RootElement.Clone());\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectSettingsV1Migration.cs#L1-L28","documentation":"Thrown by OpenIdConnectSettingsV1Migration.MigrateAsync when the persisted v1 OpenID Connect settings JSON does not parse into a JSON object. The migration upgrades stored settings (v1 -> v2) by moving 'authority' to 'discoveryUrl' and setting PKCE/client-auth defaults, and it refuses to operate on non-object payloads.","triggerScenarios":"MigrateAsync receives a JsonElement whose ValueKind is not Object (e.g. null, array, string, number) — typically because a workflow-definition or configuration store holds corrupt or wrongly-shaped settings JSON under the OpenID Connect activity/feature key.","commonSituations":"Manual edits to exported workflow JSON; an upgrade/import wrote settings as a bare string; an earlier tool truncated or replaced the settings object with a scalar; migrating definitions created by another module into an OIDC field.","solutions":["Open the persisted settings JSON and make it a proper object containing the v1 fields (authority, clientId, etc.) before re-running migration.","If the settings value is unrecoverable, delete/replace the record and re-enter the OpenID Connect configuration in the Studio/admin UI so it is saved at the current schema version.","Verify which storage row/workflow definition carries the corrupt payload (query the settings column and inspect its JSON type).","Re-export/import workflows ensuring the settings node is serialized as an object, not a stringified or scalar value."],"exampleFix":"// persisted settings before\n\"settings\": \"https://idp.example.com\"\n// after\n\"settings\": { \"authority\": \"https://idp.example.com\", \"clientId\": \"app\" }","handlingStrategy":"validation","validationCode":"using var doc = JsonDocument.Parse(settingsRaw);\nif (doc.RootElement.ValueKind != JsonValueKind.Object)\n    throw new InvalidOperationException(\"OIDC settings must be a JSON object before migration\");","typeGuard":null,"tryCatchPattern":"try { migrated = await migration.MigrateAsync(settings, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"must be an object\"))\n{\n    logger.LogError(ex, \"Persisted OIDC settings are corrupt; re-enter the configuration\");\n}","preventionTips":["Never hand-edit persisted settings JSON; edit through the admin UI","Validate settings JSON shape after import/export round-trips","Keep migration tests for stored settings before upgrading environments","Backup settings columns before schema-version migrations"],"tags":["migration","json","configuration","openid-connect"],"backgroundTag":"schema-validation-failed","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}