{"record":{"id":"39551b69a2d033c0","repo":"roboflow/supervision","slug":"malformed-compressed-rle-string-unexpected-end-at","errorCode":null,"errorMessage":"Malformed compressed RLE string: unexpected end at position {i}","messagePattern":"Malformed compressed RLE string: unexpected end at position (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/converters.py","lineNumber":439,"sourceCode":"        ValueError: If the string is truncated mid-integer.\n\n    Examples:\n        ```pycon\n        >>> from supervision.detection.utils.converters import _base48_decode\n        >>> _base48_decode(\"52203\")\n        [5, 2, 2, 0, 3]\n\n        ```\n    \"\"\"\n    values: list[int] = []\n    i = 0\n    while i < len(s):\n        x = 0\n        k = 0\n        more = True\n        while more:\n            if i >= len(s):\n                raise ValueError(\n                    f\"Malformed compressed RLE string: unexpected end at position {i}\"\n                )\n            c = ord(s[i]) - 48\n            x |= (c & 0x1F) << (5 * k)\n            more = bool(c & 0x20)\n            i += 1\n            k += 1\n            if not more and (c & 0x10):\n                x |= ~0 << (5 * k)\n        values.append(x)\n    return values\n\n\ndef _base48_encode(values: list[int]) -> str:\n    \"\"\"Encode raw (delta-encoded) integers to a COCO base-48 string.\n\n    The inverse of :func:`_base48_decode`. Applies the same variable-length\n    base-48 codec used by pycocotools.","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/converters.py#L421-L457","documentation":"The compressed-RLE decoder reads a base-48-style variable-length integer stream where each character contributes 5 bits and bit 0x20 marks continuation. If the string ends in the middle of a multi-character integer (continuation bit still set), the stream is truncated and the decoder raises with the offending position so you can locate the cut.","triggerScenarios":"Passing a compressed RLE string that was truncated by a length limit, character-set filtering (e.g. non-ASCII-safe transport stripping chars), URL/JSON escaping damage, or manual copy-paste that dropped trailing characters.","commonSituations":"RLE strings stored in text columns with truncation; transporting via systems that mangle the alphabet (code-page conversions); concatenating or slicing encoded strings; stale data encoded by an older encoder version.","solutions":["Re-encode the mask with sv.mask_to_rle(mask, compressed=True) and compare lengths to detect truncation.","Store compressed RLEs in binary-safe columns or verify a checksum alongside the string.","If decoding untrusted input, wrap in try/except ValueError and drop/re-request the record.","Pass counts as a plain list[int] (compressed=False) where transport safety is uncertain."],"exampleFix":"# before\n mask = sv.rle_to_mask(rle=row[\"rle\"][:255], resolution_wh=wh)  # column truncated\n\n# after\n mask = sv.rle_to_mask(rle=row[\"rle\"], resolution_wh=wh)  # full string from TEXT/CLOB column","handlingStrategy":"try-catch","validationCode":"def looks_like_compressed_rle(s: str) -> bool:\n    # base-48 alphabet: chars 48..95 of ASCII; and must not end mid-integer\n    return bool(s) and all(48 <= ord(c) <= 95 for c in s)","typeGuard":"def is_complete_compressed_rle(s: str) -> bool:\n    if not s:\n        return False\n    if any(ord(c) < 48 or ord(c) > 95 for c in s):\n        return False\n    return not bool(ord(s[-1]) - 48 & 0x20)  # last char must not set continuation bit","tryCatchPattern":"try:\n    mask = sv.rle_to_mask(rle=rle_string, resolution_wh=wh)\nexcept ValueError as e:\n    logger.error(\"Corrupt RLE record %s: %s\", record_id, e)\n    return None  # or re-fetch the record","preventionTips":["Use TEXT/CLOB columns or binary-safe storage for compressed RLE strings.","Store a length or checksum beside the string and verify before decoding.","Fall back to plain list[int] counts when transport is not ASCII-safe."],"tags":["rle","decoding","data-corruption","truncation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}