{"record":{"id":"a947ac96656a428c","repo":"elsa-workflows/elsa-core","slug":"adapter-adaptertype-does-not-provide-a-settings-migration","errorCode":null,"errorMessage":"Adapter '{adapterType}' does not provide a settings migration from version {version}.","messagePattern":"Adapter '(.+?)' does not provide a settings migration from version (.+?)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication/Services/AdapterSettingsMigrationService.cs","lineNumber":40,"sourceCode":"        CancellationToken cancellationToken = default)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        if (!adapters.TryGet(adapterType, out var adapter))\n            throw new InvalidOperationException($\"The adapter type '{adapterType}' is not installed or deployment-allowed.\");\n\n        var currentVersion = adapter.Describe().SettingsVersion;\n        if (settingsVersion <= 0 || settingsVersion > currentVersion)\n            throw new InvalidOperationException($\"Settings version {settingsVersion} is not compatible with adapter '{adapterType}' version {currentVersion}.\");\n        if (settingsVersion == currentVersion)\n            return new(currentVersion, settings.Clone(), false);\n\n        var migrated = settings.Clone();\n        var version = settingsVersion;\n        var stepCount = 0;\n        while (version < currentVersion)\n        {\n            if (!_migrations.TryGetValue((adapterType, version), out var migration))\n                throw new InvalidOperationException($\"Adapter '{adapterType}' does not provide a settings migration from version {version}.\");\n            if (migration.ToVersion <= version || migration.ToVersion > currentVersion)\n                throw new InvalidOperationException($\"Adapter '{adapterType}' has an invalid settings migration from version {version} to {migration.ToVersion}.\");\n            if (++stepCount > 64)\n                throw new InvalidOperationException($\"Adapter '{adapterType}' settings migration contains a cycle.\");\n\n            migrated = (await migration.MigrateAsync(migrated, cancellationToken)).Clone();\n            version = migration.ToVersion;\n        }\n\n        return new(version, migrated, true);\n    }\n\n    private static IReadOnlyDictionary<(string AdapterType, int FromVersion), IAdapterSettingsMigration> BuildMigrationIndex(\n        IEnumerable<IAdapterSettingsMigration> migrations)\n    {\n        var result = new Dictionary<(string AdapterType, int FromVersion), IAdapterSettingsMigration>();\n        foreach (var migration in migrations)\n        {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication/Services/AdapterSettingsMigrationService.cs#L22-L58","documentation":"During the forward-migration loop, MigrateAsync looks up a migration registered for (adapterType, version) to step settings toward the adapter's current version. If no migration is registered for the current source version, the chain is broken and this error is thrown rather than silently skipping.","triggerScenarios":"Settings stored at version N where the adapter registered no IAdapterSettingsMigration with FromVersion == N — e.g. adapter jumped from v1 to v3 and only a 1→3 migration exists, leaving no 2→3 step for settings at v2.","commonSituations":"Adapter upgrades that skipped registering an intermediate migration step; custom adapters shipped without migration classes; deleting an old migration class too early while old-version settings persist.","solutions":["Register the missing IAdapterSettingsMigration for that (adapterType, FromVersion) in the adapter's service configuration.","Ship a direct migration from the stored version to the current version.","One-off: manually migrate the stored settings JSON and bump its version."],"exampleFix":"// before\n// no migration registered from version 2\n// after\nservices.AddSingleton<IAdapterSettingsMigration>(new MyAdapterSettingsMigration(fromVersion: 2, toVersion: 3, migrate: s => s));","handlingStrategy":"try-catch","validationCode":"var current = adapters.Get(type).Describe().SettingsVersion;\nfor (int v = storedVersion; v < current; v++)\n    if (!migrationIndex.ContainsKey((type, v))) throw new InvalidOperationException($\"Missing migration step {v} for {type}\");","typeGuard":null,"tryCatchPattern":"try { await service.MigrateAsync(type, v, settings); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"does not provide a settings migration\"))\n{ /* halt migration; ship missing step or manual migration */ }","preventionTips":["Every adapter version bump must include the migration step","Startup validation walking the full migration chain","Keep old migrations until no stored settings can reference them"],"tags":["configuration","migration","versioning"],"backgroundTag":"missing-dependency","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"}