SubtitleEdit/subtitleedit · error · ArgumentException

Invalid version format

Error message

Invalid version format

What it means

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.

Source

Thrown at src/ui/Logic/SematicVersion.cs:24

public class SemanticVersion
{
    public int Major { get; set; }
    public int Minor { get; set; }
    public int Patch { get; set; }
    public string PreRelease { get; set; }
    public int PreReleaseNumber { get; set; }
    public int PreReleaseRank { get; set; }

    public SemanticVersion(string input)
    {
        var trimmedInput = input.Trim();
        PreRelease = string.Empty;
        var version = trimmedInput.StartsWith("v") ? trimmedInput.Substring(1) : trimmedInput;

        var match = Regex.Match(version, @"^(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)(\d+)?)?$", RegexOptions.IgnoreCase);
        if (!match.Success)
        {
            throw new ArgumentException("Invalid version format", nameof(trimmedInput));
        }

        Major = int.Parse(match.Groups[1].Value);
        Minor = int.Parse(match.Groups[2].Value);
        Patch = int.Parse(match.Groups[3].Value);

        if (match.Groups[4].Success)
        {
            PreRelease = match.Groups[4].Value.ToLowerInvariant();
            PreReleaseRank = GetPreReleaseRank(PreRelease);
            PreReleaseNumber = match.Groups[5].Success ? int.Parse(match.Groups[5].Value) : 0;
        }
        else
        {
            PreRelease = string.Empty;
            PreReleaseRank = int.MaxValue; // final/stable is considered highest
        }
    }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Normalize input to MAJOR.MINOR.PATCH[-wordNNN] before constructing SemanticVersion (strip build metadata after '+').
  2. Validate with the same regex before calling the constructor and surface a clear error to the user.
  3. If richer SemVer (dotted prerelease, build metadata) is genuinely needed, extend the regex or adopt a dedicated SemVer parser.
  4. Provide a TryParse-style wrapper that returns a default instead of throwing for untrusted input.

Example fix

// before
var v = new SemanticVersion(rawVersion);

// after
private static readonly Regex Fmt = new(@"^(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)(\d+)?)?$", RegexOptions.IgnoreCase);
static SemanticVersion? ParseSafe(string raw)
{
    var core = (raw ?? "").Trim().TrimStart('v').Split('+')[0];
    return Fmt.IsMatch(core) ? new SemanticVersion(raw) : null;
}
Defensive patterns

Strategy: validation

Validate before calling

private static readonly Regex SemVerFmt = new(@"^(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)(\d+)?)?$", RegexOptions.IgnoreCase);
static bool IsValid(string raw)
{
    var core = (raw ?? "").Trim().TrimStart('v').Split('+')[0];
    return SemVerFmt.IsMatch(core);
}

Try / catch

SemanticVersion v;
try { v = new SemanticVersion(raw); }
catch (ArgumentException) { v = new SemanticVersion("0.0.0"); logger.LogWarning("Unparsable version '{Raw}', defaulting", raw); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/c73e817342640d82. Report an issue: GitHub.