{"record":{"id":"ead5ae0cb537fe35","repo":"elsa-workflows/elsa-core","slug":"adapter-adaptertype-has-an-invalid-settings-migration-from","errorCode":null,"errorMessage":"Adapter '{adapterType}' has an invalid settings migration from version {version} to {migration.ToVersion}.","messagePattern":"Adapter '(.+?)' has an invalid settings migration from version (.+?) to (.+?)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication/Services/AdapterSettingsMigrationService.cs","lineNumber":42,"sourceCode":"        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        {\n            if (string.IsNullOrWhiteSpace(migration.AdapterType) || migration.FromVersion <= 0)\n                throw new InvalidOperationException(\"Adapter settings migrations must define an adapter type and a positive source version.\");","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication/Services/AdapterSettingsMigrationService.cs#L24-L60","documentation":"Each registered migration must move the version strictly forward (ToVersion > FromVersion) and never beyond the adapter's current version. MigrateAsync throws this when a migration's ToVersion violates either invariant, protecting the loop from non-progress or overshoot.","triggerScenarios":"An IAdapterSettingsMigration registered with ToVersion <= FromVersion (backwards or same-version), or ToVersion greater than adapter.Describe().SettingsVersion (e.g. adapter downgraded but migrations not updated).","commonSituations":"Copy-paste mistakes in migration definitions; declaring migrations for a future adapter version that isn't deployed yet; off-by-one in version constants.","solutions":["Fix the migration's ToVersion so it is greater than FromVersion and <= the adapter's current SettingsVersion.","Remove or gate migrations targeting versions newer than the deployed adapter.","Add a startup validation that walks each adapter's migration chain and checks monotonicity."],"exampleFix":"// before\nnew AdapterSettingsMigration(\"my-adapter\", fromVersion: 3, toVersion: 3, ...)\n// after\nnew AdapterSettingsMigration(\"my-adapter\", fromVersion: 3, toVersion: 4, ...)","handlingStrategy":"validation","validationCode":"if (m.ToVersion <= m.FromVersion || m.ToVersion > currentVersion)\n    throw new InvalidOperationException($\"Invalid migration {m.FromVersion}->{m.ToVersion} for {m.AdapterType}\");","typeGuard":null,"tryCatchPattern":"try { await service.MigrateAsync(type, v, settings); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"invalid settings migration\"))\n{ /* fix migration registration and redeploy */ }","preventionTips":["Unit-test each migration's version invariants","Don't ship migrations for unreleased adapter versions","Use constants for version numbers to avoid off-by-one"],"tags":["configuration","migration","versioning"],"backgroundTag":"invalid-config-value","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"}