{"record":{"id":"93cb8c3234b4dfc3","repo":"dotnet/runtime","slug":"invalid-debian-version-format-version","errorCode":null,"errorMessage":"Invalid Debian version format: {version}","messagePattern":"Invalid Debian version format: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"eng/common/cross/install-debs.py","lineNumber":160,"sourceCode":"def parse_release_file(content, path):\n    \"\"\"Parses the Release file and returns sha256 checksum of the specified path.\"\"\"\n\n    # data looks like this:\n    # <checksum>  <size>  <path>\n    matches = re.findall(r'^ (\\S*) +(\\S*) +(\\S*)$', content, re.MULTILINE)\n\n    for entry in matches:\n        # the file has both md5 and sha256 checksums, we want sha256 which has a length of 64\n        if entry[2] == path and len(entry[0]) == 64:\n            return entry[0]\n\n    raise Exception(f\"Could not find checksum for {path} in Release file.\")\n\ndef parse_debian_version(version):\n    \"\"\"Parse a Debian package version into epoch, upstream version, and revision.\"\"\"\n    match = re.match(r'^(?:(\\d+):)?([^-]+)(?:-(.+))?$', version)\n    if not match:\n        raise ValueError(f\"Invalid Debian version format: {version}\")\n    epoch, upstream, revision = match.groups()\n    return int(epoch) if epoch else 0, upstream, revision or \"\"\n\ndef compare_upstream_version(v1, v2):\n    \"\"\"Compare upstream or revision parts using Debian rules.\"\"\"\n    def tokenize(version):\n        tokens = re.split(r'([0-9]+|[A-Za-z]+)', version)\n        return [int(x) if x.isdigit() else x for x in tokens if x]\n\n    tokens1 = tokenize(v1)\n    tokens2 = tokenize(v2)\n\n    for token1, token2 in zip(tokens1, tokens2):\n        if type(token1) == type(token2):\n            if token1 != token2:\n                return (token1 > token2) - (token1 < token2)\n        else:\n            return -1 if isinstance(token1, str) else 1","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/eng/common/cross/install-debs.py#L142-L178","documentation":"Raised by parse_debian_version() in install-debs.py when a Debian package version string fails to match the regex '^(?:(\\d+):)?([^-]+)(?:-(.+))$'. This regex expects an optional numeric epoch prefix (colon-separated), a mandatory upstream version, and an optional hyphen-separated revision. The function is called transitively from parse_package_index() via compare_debian_versions() to select the highest available package version during rootfs creation.","triggerScenarios":"Triggered when the Packages.gz index downloaded from the Debian/Ubuntu mirror contains a Version field that the regex cannot parse. For example, a version like '1:1.2:3' (multiple colons), an empty upstream segment like ':1.2.3', or a version containing only a revision with no upstream part. The call chain is parse_package_index -> compare_debian_versions -> parse_debian_version.","commonSituations":"Happens when the mirror returns package metadata with non-standard version strings, when a custom or exotic distribution uses a non-Debian versioning scheme, or when the Packages index is truncated/corrupted mid-download. Also possible when the mirror serves packages from a suite with native versioning that deviates from Debian policy (e.g., some embedded or ports repositories).","solutions":["Inspect the downloaded Packages index for the offending version string by grepping for 'Version:' lines and checking for malformed entries.","Verify the --suite and --mirror arguments point to a valid Debian-compatible repository that follows Debian version policy.","If the version is valid per Debian policy but the regex is too strict, extend the regex in parse_debian_version() to handle the edge case.","Switch to a different mirror or suite that provides well-formed package metadata."],"exampleFix":"# before\nmatch = re.match(r'^(?:(\\d+):)?([^-]+)(?:-(.+))?$', version)\nif not match:\n    raise ValueError(f\"Invalid Debian version format: {version}\")\n\n# after - allow colon in upstream version for epoch-like native versions\nmatch = re.match(r'^(?:(\\d+):)?(.+?)(?:-([^-]+))?$', version)\nif not match:\n    raise ValueError(f\"Invalid Debian version format: {version}\")","handlingStrategy":"validation","validationCode":"import re\n\ndef is_valid_debian_version(version: str) -> bool:\n    \"\"\"Check if a version string matches Debian version format before passing to parse_debian_version.\"\"\"\n    return re.match(r'^(?:(\\d+):)?([^-]+)(?:-(.+))?$', version) is not None\n\n# Usage before calling compare_debian_versions:\nif not is_valid_debian_version(version_str):\n    print(f\"Warning: skipping malformed version: {version_str}\")\n    continue","typeGuard":"null","tryCatchPattern":"try:\n    epoch, upstream, revision = parse_debian_version(version)\nexcept ValueError as e:\n    logging.warning(f\"Skipping package with unparseable version: {e}\")\n    continue  # skip this package rather than aborting the entire rootfs build","preventionTips":["Validate version strings from external sources before parsing.","Log the raw version string when parsing fails for post-mortem analysis.","Pin to known-good mirror/suite combinations that produce standard Debian versions.","Add unit tests for parse_debian_version covering edge cases like epoch, native, and empty revision."],"tags":["debian","packaging","versioning","rootfs","validation"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}