{"record":{"id":"95d4b0145bc4559c","repo":"stamparm/maltrail","slug":"r-is-not-major-minor-maltrail-versions-two-components","errorCode":null,"errorMessage":"[!] %r is not 'major.minor' - Maltrail versions two components","messagePattern":"\\[!\\] %r is not 'major\\.minor' - Maltrail versions two components","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"sensor/tools/bump_version.py","lineNumber":135,"sourceCode":"def main():\n    parser = argparse.ArgumentParser(description=\"set Maltrail's version in every file that carries it\")\n    parser.add_argument(\"version\", nargs=\"?\", help=\"the new version, e.g. 3.3\")\n    parser.add_argument(\"--next\", action=\"store_true\", help=\"bump the minor component of the current version\")\n    parser.add_argument(\"--check\", action=\"store_true\", help=\"verify only; write nothing\")\n    parser.add_argument(\"--date\", help=\"also set CITATION.cff date-released (YYYY-MM-DD, or 'today')\")\n    args = parser.parse_args()\n\n    if args.check:\n        if args.version or args.next:\n            parser.error(\"--check takes no version\")\n        return _verify()\n\n    if args.next == bool(args.version):\n        parser.error(\"give a version, or --next, but not both\")\n\n    version = next_minor(current()) if args.next else args.version\n    if not re.match(r'^\\d+\\.\\d+$', version):\n        raise SystemExit(\"[!] %r is not 'major.minor' - Maltrail versions two components\" % version)\n\n    date = args.date\n    if date == \"today\":\n        date = datetime.date.today().isoformat()\n    if date and not re.match(r'^\\d{4}-\\d{2}-\\d{2}$', date):\n        raise SystemExit(\"[!] --date must be YYYY-MM-DD\")\n\n    print(\"[i] %s -> %s\" % (current(), version))\n    apply(version, date)\n    return _verify()\n\n\ndef _verify():\n    \"\"\"Hand off to the checker rather than re-implementing agreement here.\n\n    argv is swapped for the call: check_version parses sys.argv itself, and would otherwise\n    reject the flags that were meant for THIS script.\n    \"\"\"","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/tools/bump_version.py#L117-L153","documentation":"main() validates the final target version (explicit --version or computed via --next) against ^\\d+\\.\\d+$. Maltrail's versioning scheme is strictly two components (major.minor), so anything else - pre-release suffixes, three-part semver, or non-numeric parts - is rejected before any file is touched.","triggerScenarios":"Running `python bump_version.py --version 0.5.3`, `--version 0.5-rc1`, `--version v0.5`, or otherwise passing a string that is not exactly digits.digits.","commonSituations":"A developer habitually uses semver with three components or pre-release tags in other projects and applies it here; CI scripts pass a build-stamped version; a tag prefix like 'v' is included.","solutions":["Pass exactly two numeric components: python bump_version.py --version 0.54.","Remove prefixes/suffixes (v, -rc1, +build) from the version string before invoking the script.","If you genuinely need three-component versions, this tool's contract must change - update the regex and next_minor(), but note Maltrail upstream uses major.minor only."],"exampleFix":"// before\n$ python bump_version.py --version 0.5.3\n// after\n$ python bump_version.py --version 0.54","handlingStrategy":"validation","validationCode":"import re\ndef valid_target(v: str) -> bool:\n    return bool(re.match(r'^\\d+\\.\\d+$', v))\nassert valid_target('0.54'), 'pass a major.minor version, e.g. --version 0.54'\n","typeGuard":"import re\ndef is_maltrail_version(v: str) -> bool:\n    return isinstance(v, str) and re.match(r'^\\d+\\.\\d+$', v) is not None\n","tryCatchPattern":"try:\n    bump_version.main(['--version', args.version])\nexcept SystemExit as e:\n    if \"is not 'major.minor'\" in str(e):\n        print('Use a two-component version, e.g. --version 0.54')\n","preventionTips":["Remember Maltrail uses only major.minor - no semver patch or pre-release parts","Strip 'v' prefixes and build metadata from CI-generated version strings before invoking","Use --next when you just want the minor bumped instead of hand-writing versions"],"tags":["versioning","cli","validation"],"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"}