{"record":{"id":"ab138979fceaf387","repo":"stride3d/stride","slug":"the-target-version-is-lower-or-equal-to-the-start-version","errorCode":null,"errorMessage":"The target version is lower or equal to the start version.","messagePattern":"The target version is lower or equal to the start version\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/AssetUpgraderAttribute.cs","lineNumber":27,"sourceCode":"public class AssetUpgraderAttribute : Attribute\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AssetUpgraderAttribute\"/> with a range of supported initial version numbers.\n    /// </summary>\n    /// <param name=\"name\">The dependency name.</param>\n    /// <param name=\"startMinVersion\">The minimal initial version number this upgrader can work on.</param>\n    /// <param name=\"targetVersion\">The target version number of this upgrader.</param>\n    /// <param name=\"assetUpgraderType\">The type of upgrader to instantiate to upgrade the asset.</param>\n    public AssetUpgraderAttribute(string name, string startMinVersion, string targetVersion, Type assetUpgraderType)\n    {\n        Name = name;\n        StartVersion = PackageVersion.Parse(startMinVersion);\n        TargetVersion = PackageVersion.Parse(targetVersion);\n\n        if (!typeof(IAssetUpgrader).IsAssignableFrom(assetUpgraderType))\n            throw new ArgumentException(\"The assetUpgraderType must implement IAssetUpgrader interface\", nameof(assetUpgraderType));\n        if (TargetVersion <= StartVersion)\n            throw new ArgumentException(\"The target version is lower or equal to the start version.\", nameof(targetVersion));\n        AssetUpgraderType = assetUpgraderType;\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AssetUpgraderAttribute\"/> with a single supported initial version number.\n    /// </summary>\n    /// <param name=\"name\">The dependency name.</param>\n    /// <param name=\"startVersion\">The initial version number this upgrader can work on.</param>\n    /// <param name=\"targetVersion\">The target version number of this upgrader.</param>\n    /// <param name=\"assetUpgraderType\">The type of upgrader to instantiate to upgrade the asset.</param>\n    public AssetUpgraderAttribute(string name, int startVersion, int targetVersion, Type assetUpgraderType)\n        : this(name, \"0.0.\" + startVersion, \"0.0.\" + targetVersion, assetUpgraderType)\n    {\n    }\n\n    /// <summary>\n    /// Gets or sets the dependency name.\n    /// </summary>","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/AssetUpgraderAttribute.cs#L9-L45","documentation":"AssetUpgraderAttribute's constructor parses startMinVersion and targetVersion into PackageVersion and enforces that the upgrade range moves forward: TargetVersion must be strictly greater than StartVersion. The library uses these ranges to build an ordered chain of asset upgraders, so a non-advancing (or backwards) range would be meaningless and break the upgrade graph. It throws ArgumentException naming targetVersion when TargetVersion <= StartVersion.","triggerScenarios":"Constructing AssetUpgraderAttribute (or the derived attribute used on asset upgrader classes) with a targetVersion string that parses equal to or lower than startMinVersion, e.g. [AssetUpgrader(\"4.1.0.0\", \"4.0.0.0\", typeof(MyUpgrader))] or equal versions [AssetUpgrader(\"4.1.0.0\", \"4.1.0.0\", ...)].","commonSituations":"Copy-pasting an existing upgrader attribute and forgetting to bump targetVersion after bumping startVersion; swapping the two version arguments by mistake; authoring a no-op upgrader with identical start/target versions; refactoring version constants so they resolve to the same value.","solutions":["Ensure targetVersion is strictly greater than startMinVersion in the attribute arguments.","Check for swapped argument order: the signature is (startMinVersion, targetVersion, upgraderType).","If the upgrader is a no-op for the same version range, remove it entirely instead of registering it.","Verify version constants/strings were updated when porting the upgrader to a new package version."],"exampleFix":"// before\n[AssetUpgrader(AssetUpgraderVersions.Start, \"4.1.0.0\", typeof(MyAssetUpgrader))] // Start == 4.1.0.0\n// after\n[AssetUpgrader(AssetUpgraderVersions.Start, \"4.2.0.0\", typeof(MyAssetUpgrader))] // target > start","handlingStrategy":"validation","validationCode":"var start = PackageVersion.Parse(startMinVersion);\nvar target = PackageVersion.Parse(targetVersion);\nif (target <= start)\n    throw new ArgumentException(nameof(targetVersion), $\"targetVersion ({target}) must be greater than startMinVersion ({start})\");","typeGuard":"static bool IsForwardUpgrade(PackageVersion start, PackageVersion target) => target > start;","tryCatchPattern":"try\n{\n    var attr = new AssetUpgraderAttribute(start, target, upgraderType);\n}\ncatch (ArgumentException ex) when (ex.ParamName == nameof(targetVersion))\n{\n    // log: start/target versions are not strictly increasing\n}","preventionTips":["Bump targetVersion whenever you create or copy an upgrader attribute.","Keep a unit test that instantiates every upgrader attribute in the assembly to catch bad ranges early.","Order arguments mentally as 'from, to' to avoid swapping start and target."],"tags":["argument-validation","versioning","asset-upgrade","constructor"],"backgroundTag":"invalid-argument-value","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"}