{"record":{"id":"8d9b44edf5220ee4","repo":"stride3d/stride","slug":"the-upgrader-overlaps-with-another-upgrader","errorCode":null,"errorMessage":"The upgrader overlaps with another upgrader.","messagePattern":"The upgrader overlaps with another upgrader\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/AssetUpgraderCollection.cs","lineNumber":59,"sourceCode":"        this.currentVersion = currentVersion;\n        AssetRegistry.IsAssetOrPackageType(assetType, true);\n        AssetType = assetType;\n    }\n\n    public Type AssetType { get; }\n\n    internal void RegisterUpgrader(Type upgraderType, PackageVersion startVersion, PackageVersion targetVersion)\n    {\n        lock (upgraders)\n        {\n            if (targetVersion > currentVersion)\n                throw new ArgumentException(\"The upgrader has a target version higher that the current version.\");\n\n            var range = new VersionRange(startVersion, targetVersion);\n\n            if (upgraders.Any(x => x.Key.Overlap(range)))\n            {\n                throw new ArgumentException(\"The upgrader overlaps with another upgrader.\");\n            }\n\n            upgraders.Add(new VersionRange(startVersion, targetVersion), upgraderType);\n        }\n    }\n\n    internal void Validate(PackageVersion minVersion)\n    {\n        lock (upgraders)\n        {\n            var version = minVersion;\n            foreach (var upgrader in upgraders)\n            {\n                if (!upgrader.Key.Contains(version))\n                    continue;\n\n                version = upgrader.Key.Target;\n                if (version == currentVersion)","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/AssetUpgraderCollection.cs#L41-L77","documentation":"RegisterUpgrader builds a VersionRange(startVersion, targetVersion) and checks whether any already-registered upgrader's range overlaps it. Because the collection resolves an initial version to exactly one upgrader via FirstOrDefault, ranges must be disjoint; an overlap would make upgrader selection ambiguous, so an ArgumentException is thrown.","triggerScenarios":"Calling RegisterUpgrader twice with ranges that share any version, e.g. (4.0.0.0→4.1.0.0) then (4.0.5.0→4.2.0.0); or two AssetUpgraderAttributes declaring ranges whose [start, target] intervals intersect for the same asset type.","commonSituations":"Adding a new upgrader without checking existing ones covering part of the same span; off-by-one boundaries in start/target versions of consecutive upgraders; accidentally registering the same upgrader type twice (e.g. attribute duplicated on a class or assembly scanned twice).","solutions":["Adjust the new upgrader's start/target versions so its range does not intersect any existing range.","Remove or correct the conflicting registered upgrader whose range overlaps.","Enumerate existing upgraders (or log upgraders keys) to find which VersionRange collides.","If the same upgrader was registered twice, remove the duplicate attribute/registration call."],"exampleFix":"// before\nRegisterUpgrader(typeof(UpgraderA), v(4,0,0,0), v(4,1,0,0));\nRegisterUpgrader(typeof(UpgraderB), v(4,0,5,0), v(4,2,0,0)); // overlaps UpgraderA\n// after\nRegisterUpgrader(typeof(UpgraderA), v(4,0,0,0), v(4,1,0,0));\nRegisterUpgrader(typeof(UpgraderB), v(4,1,0,0), v(4,2,0,0)); // contiguous, disjoint","handlingStrategy":"validation","validationCode":"var range = new VersionRange(start, target);\nbool overlaps = registeredRanges.Any(r => r.Overlap(range));\nif (overlaps) throw new InvalidOperationException(\"New upgrader range overlaps an existing one\");","typeGuard":"static bool IsDisjoint(VersionRange candidate, IEnumerable<VersionRange> existing) => !existing.Any(r => r.Overlap(candidate));","tryCatchPattern":"try\n{\n    collection.RegisterUpgrader(typeof(MyUpgrader), start, target);\n}\ncatch (ArgumentException)\n{\n    // inspect existing ranges and adjust start/target to be disjoint\n}","preventionTips":["Keep consecutive upgrader ranges contiguous: next range starts where the previous target ends.","Before adding an upgrader, list all existing ranges for the asset type.","Avoid duplicating upgrader attributes on classes; one registration per range."],"tags":["versioning","asset-upgrade","duplicate-registration","conflict"],"backgroundTag":"conflicting-config-options","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}