{"record":{"id":"c73e817342640d82","repo":"SubtitleEdit/subtitleedit","slug":"invalid-version-format","errorCode":null,"errorMessage":"Invalid version format","messagePattern":"Invalid version format","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/SematicVersion.cs","lineNumber":24,"sourceCode":"public class SemanticVersion\n{\n    public int Major { get; set; }\n    public int Minor { get; set; }\n    public int Patch { get; set; }\n    public string PreRelease { get; set; }\n    public int PreReleaseNumber { get; set; }\n    public int PreReleaseRank { get; set; }\n\n    public SemanticVersion(string input)\n    {\n        var trimmedInput = input.Trim();\n        PreRelease = string.Empty;\n        var version = trimmedInput.StartsWith(\"v\") ? trimmedInput.Substring(1) : trimmedInput;\n\n        var match = Regex.Match(version, @\"^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([a-z]+)(\\d+)?)?$\", RegexOptions.IgnoreCase);\n        if (!match.Success)\n        {\n            throw new ArgumentException(\"Invalid version format\", nameof(trimmedInput));\n        }\n\n        Major = int.Parse(match.Groups[1].Value);\n        Minor = int.Parse(match.Groups[2].Value);\n        Patch = int.Parse(match.Groups[3].Value);\n\n        if (match.Groups[4].Success)\n        {\n            PreRelease = match.Groups[4].Value.ToLowerInvariant();\n            PreReleaseRank = GetPreReleaseRank(PreRelease);\n            PreReleaseNumber = match.Groups[5].Success ? int.Parse(match.Groups[5].Value) : 0;\n        }\n        else\n        {\n            PreRelease = string.Empty;\n            PreReleaseRank = int.MaxValue; // final/stable is considered highest\n        }\n    }","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/SematicVersion.cs#L6-L42","documentation":"ArgumentException from the SemanticVersion constructor when input fails the regex ^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([a-z]+)(\\d+)?)?$ (IgnoreCase). It requires exactly three numeric components and an optional single-word prerelease tag optionally followed by digits; a leading 'v' is tolerated.","triggerScenarios":"Inputs that break the pattern: '1.2' (two parts), '1.2.3.4' (four parts), '1.2.3-alpha.1' (dot in prerelease), '1.2.3-rc-1' (hyphen), '1.2.3+build' (build metadata), '1.2.beta' (non-numeric component), or empty/whitespace string.","commonSituations":"Parsing full SemVer 2.0 or NuGet-style versions (dotted prerelease, +metadata), plugin manifest versions carrying build metadata, or user-typed version fields that do not match the strict shape.","solutions":["Normalize input to MAJOR.MINOR.PATCH[-wordNNN] before constructing SemanticVersion (strip build metadata after '+').","Validate with the same regex before calling the constructor and surface a clear error to the user.","If richer SemVer (dotted prerelease, build metadata) is genuinely needed, extend the regex or adopt a dedicated SemVer parser.","Provide a TryParse-style wrapper that returns a default instead of throwing for untrusted input."],"exampleFix":"// before\nvar v = new SemanticVersion(rawVersion);\n\n// after\nprivate static readonly Regex Fmt = new(@\"^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([a-z]+)(\\d+)?)?$\", RegexOptions.IgnoreCase);\nstatic SemanticVersion? ParseSafe(string raw)\n{\n    var core = (raw ?? \"\").Trim().TrimStart('v').Split('+')[0];\n    return Fmt.IsMatch(core) ? new SemanticVersion(raw) : null;\n}","handlingStrategy":"validation","validationCode":"private static readonly Regex SemVerFmt = new(@\"^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([a-z]+)(\\d+)?)?$\", RegexOptions.IgnoreCase);\nstatic bool IsValid(string raw)\n{\n    var core = (raw ?? \"\").Trim().TrimStart('v').Split('+')[0];\n    return SemVerFmt.IsMatch(core);\n}","typeGuard":null,"tryCatchPattern":"SemanticVersion v;\ntry { v = new SemanticVersion(raw); }\ncatch (ArgumentException) { v = new SemanticVersion(\"0.0.0\"); logger.LogWarning(\"Unparsable version '{Raw}', defaulting\", raw); }","preventionTips":["Validate with the same regex at the configuration boundary.","Strip build metadata (after '+') before parsing.","Document the accepted MAJOR.MINOR.PATCH[-wordNNN] format to users.","Wrap construction in a TryParse helper for untrusted input."],"tags":["semver","parsing","validation","configuration"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}