stride3d/stride · error · Exception
Could not parse a valid version from
Error message
Could not parse a valid version from {sourceFile} (MajorMinor='{majorMinor}', Patch='{patch}'). Check the 'MajorMinor = "x.y";' and 'Patch = "n";' lines. What it means
StrideVersionTasks.ReadInputs parses version fields (MajorMinor, Patch, NuGetVersionSuffix) out of a source file via regex and validates them before building the composed version string. If MajorMinor does not match 'x.y' or Patch is not a number, it throws with the parsed values and the file path, so a malformed version is never silently propagated into packages or compiled constants.
Solutions
- Open the file named in the message and fix the MajorMinor/Patch lines to the exact shapes MajorMinor = "4.2"; and Patch = "1";.
- Restore the version file from git (git checkout -- <file>) if the lines were accidentally changed or deleted.
- Re-run whatever tool injects version properties into the file before invoking ReadInputs.
- Check for merge-conflict markers or commented-out lines inside the version file.
Example fix
// before (StrideVersion.props) <PropertyGroup><MajorMinor>4</MajorMinor><Patch></Patch></PropertyGroup> // after // MajorMinor = "4.2"; // Patch = "1";
Defensive patterns
Strategy: validation
Validate before calling
static void ValidateVersionFile(string path)
{
var data = File.ReadAllText(path);
var mm = Regex.Match(data, "MajorMinor = \"([^\"]*)\";").Groups[1].Value;
var patch = Regex.Match(data, "Patch = \"([^\"]*)\";").Groups[1].Value;
if (!Regex.IsMatch(mm, @"^[0-9]+\.[0-9]+$") || !Regex.IsMatch(patch, @"^[0-9]+$"))
throw new InvalidOperationException($"{path} has invalid MajorMinor='{mm}' or Patch='{patch}'.");
} Type guard
static bool IsWellFormedVersion(string majorMinor, string patch) =>
Regex.IsMatch(majorMinor ?? "", @"^[0-9]+\.[0-9]+$") &&
Regex.IsMatch(patch ?? "", @"^[0-9]+$"); Try / catch
try
{
versionTasks.ReadInputs();
}
catch (Exception ex) when (ex.Message.Contains("Could not parse a valid version from"))
{
logger.Error($"Version source file malformed: {ex.Message}. Restore MajorMinor/Patch lines.");
throw;
} Prevention
- Keep the version file in the exact 'Name = "value";' line format and never hand-edit it mid-release.
- Add a schema/lint check of the version file to CI before build tasks run.
- Resolve merge conflicts in the version file by regenerating it, not hand-merging.
When it happens
Trigger: Calling ReadInputs when the version source file's 'MajorMinor = "x.y";' or 'Patch = "n";' lines are missing, renamed, commented out, reformatted (e.g. extra spaces, single quotes), or contain placeholders/empty strings — Field() then returns "" and the regex checks fail.
Common situations: Manual edits to the version file during release prep; branch merges dropping the version block; CI checking out a file where version props are injected by another tool that didn't run; accidental change of assignment style ("=" spacing or semicolon removed).
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid version dependency format. Unable to decode
- Invalid version format. Unable to decode
- Invalid version format
- Asset of type has been serialized with newer version , but…
- Asset of type should be updated from version to , but no…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/b1385ff90a7d143d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/targets/StrideVersionTasks.cs:35
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
// Shared version logic for both the dev and release generators.
internal static class StrideVersionUtil
{
// Reads the editable inputs from SharedAssemblyInfo.cs. The version is composed MajorMinor.Patch (Patch is the
// only patch source; MajorMinor the only major.minor source — no duplication to drift).
public static void ReadInputs(string sourceFile, out string majorMinor, out string version, out string suffix)
{
string data = File.ReadAllText(sourceFile);
majorMinor = Field(data, "MajorMinor");
string patch = Field(data, "Patch");
suffix = Field(data, "NuGetVersionSuffix");
// Fail loudly on an unparseable version rather than emit a malformed one (e.g. "." or "4.4.") that would
// ship a weird package or compile a garbage const. Field returns "" when a line's shape changed.
if (!Regex.IsMatch(majorMinor, @"^[0-9]+\.[0-9]+$") || !Regex.IsMatch(patch, @"^[0-9]+$"))
throw new Exception("Could not parse a valid version from " + sourceFile + " (MajorMinor='" + majorMinor +
"', Patch='" + patch + "'). Check the 'MajorMinor = \"x.y\";' and 'Patch = \"n\";' lines.");
version = majorMinor + "." + patch;
}
private static string Field(string data, string name)
=> Regex.Match(data, name + " = \"([^\"]*)\";").Groups[1].Value;
public static string Git(string workingDir, string args)
{
var psi = new ProcessStartInfo("git", args)
{
WorkingDirectory = workingDir,
RedirectStandardOutput = true,
UseShellExecute = false
};
using (var p = Process.Start(psi))
{
string output = p.StandardOutput.ReadToEnd().Trim();View on GitHub (pinned to 96fad776d2)