{"record":{"id":"e2d7026c70d74e1d","repo":"stamparm/maltrail","slug":"version-r-has-non-numeric-components","errorCode":null,"errorMessage":"[!] version %r has non-numeric components","messagePattern":"\\[!\\] version %r has non-numeric components","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"sensor/tools/check_version.py","lineNumber":117,"sourceCode":"        raise SystemExit(\"[!] no maltrail-sensor package entry found in %s\" % CARGO_LOCK)\n    return match.group(1)\n\n\ndef series(version):\n    \"\"\"'3.0.1' and '3.0' both reduce to (3, 0) - Maltrail versions two components, Cargo three.\n\n    A SemVer pre-release / build suffix is stripped first, so 'v3.0-rc1' and '3.0.0+deb' are the\n    3.0 series like anything else. Release candidates are the whole point of having a release\n    pipeline that can be rehearsed, and refusing to name one would have made that impossible.\n    \"\"\"\n    version = re.split(r\"[-+]\", version, 1)[0]\n    parts = version.split('.')\n    if len(parts) < 2:\n        raise SystemExit(\"[!] version %r is not 'major.minor[.patch]'\" % version)\n    try:\n        return (int(parts[0]), int(parts[1]))\n    except ValueError:\n        raise SystemExit(\"[!] version %r has non-numeric components\" % version)\n\n\ndef main():\n    parser = argparse.ArgumentParser(description=\"check that the sensor, the server and CITATION.cff agree on the version\")\n    parser.add_argument(\"--tag\", help=\"also require both to match this release tag (e.g. '3.0' or 'v3.0')\")\n    args = parser.parse_args()\n\n    settings, cargo, citation = settings_version(), cargo_version(), citation_version()\n    generated, locked = settings_gen_version(), cargo_lock_version()\n    print(\"[i] core/settings.py VERSION   = %s\" % settings)\n    print(\"[i] sensor/Cargo.toml version  = %s\" % cargo)\n    print(\"[i] CITATION.cff version       = %s\" % citation)\n    print(\"[i] settings_gen.rs VERSION    = %s\" % generated)\n    print(\"[i] Cargo.lock version         = %s\" % locked)\n\n    if series(settings) != series(cargo):\n        print(\"[x] the server and the sensor would report different versions\", file=sys.stderr)\n        print(\"[?] make sensor/Cargo.toml '%s.0' or core/settings.py '%d.%d'\"","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/tools/check_version.py#L99-L135","documentation":"series() converts the first two dot-separated components of a version to integers. If either component is non-numeric (e.g. '3.x', 'latest', or letters in the major/minor slot), int() raises ValueError and the tool exits with this message. Pre-release/build suffixes after '-' or '+' are already stripped, so this only fires for genuinely non-numeric major/minor parts.","triggerScenarios":"A version string whose major or minor component is not an integer after stripping any [-+] suffix — e.g. 'three.0', '3.x', '3.0.dev' is fine (suffix) but '3.dev.0' is not — when passed via --tag or read from a version file.","commonSituations":"Placeholder or template text left in a version file ('latest', 'X.Y'); a typo like '3,O' in Cargo.toml or CITATION.cff; semver2 variants with letters in the numeric positions.","solutions":["Correct the version in the offending source (CITATION.cff, Cargo.toml/lock, settings mirror) to numeric major.minor[.patch]","Use pre-release suffixes instead of letters in components: '3.0.0-rc1' rather than '3.rc1'","Grep the version sources for non-numeric components before running the checker","Re-run check_version.py to verify the fix"],"exampleFix":"// before (CITATION.cff)\nversion: \"3.rc1\"\n// after\nversion: \"3.0.0-rc1\"","handlingStrategy":"validation","validationCode":"import re\ndef is_numeric_version(v):\n    v = re.split(r'[-+]', v, 1)[0]\n    parts = v.split('.')\n    return len(parts) >= 2 and all(p.isdigit() for p in parts[:2])","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never put placeholder text like 'latest' in version fields","Use semver pre-release suffixes instead of letters in numeric slots","Lint version files for numeric components before releases"],"tags":["python","versioning","semver"],"backgroundTag":"invalid-argument-format","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}