{"record":{"id":"b4e77e3c5795aa4d","repo":"canopy-network/canopy","slug":"item-too-long-len-item-bytes-max-255","errorCode":null,"errorMessage":"Item too long: {len(item)} bytes (max 255)","messagePattern":"Item too long: (.+?) bytes \\(max 255\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"plugin/python/contract/contract.py","lineNumber":90,"sourceCode":"}\n\n\n# State key prefixes (matching Go)\nACCOUNT_PREFIX = b\"\\x01\"\nPOOL_PREFIX = b\"\\x02\"\nPARAMS_PREFIX = b\"\\x07\"\n\n\n# Key generation functions (from keys.py)\n\ndef join_len_prefix(*items: Optional[bytes]) -> bytes:\n    \"\"\"Join byte arrays with length prefixes.\"\"\"\n    result = bytearray()\n    for item in items:\n        if not item:\n            continue\n        if len(item) > 255:\n            raise ValueError(f\"Item too long: {len(item)} bytes (max 255)\")\n        result.append(len(item))\n        result.extend(item)\n    return bytes(result)\n\n\ndef format_uint64(value: Union[int, str]) -> bytes:\n    \"\"\"Format uint64 as big-endian bytes.\"\"\"\n    if isinstance(value, str):\n        value = int(value)\n    if not isinstance(value, int) or value < 0 or value >= (1 << 64):\n        raise ValueError(f\"Invalid uint64 value: {value}\")\n    return struct.pack('>Q', value)\n\n\ndef key_for_account(address: bytes) -> bytes:\n    \"\"\"Generate state database key for an account.\"\"\"\n    return join_len_prefix(ACCOUNT_PREFIX, address)\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/plugin/python/contract/contract.py#L72-L108","documentation":"join_len_prefix builds blockchain state keys by joining byte arrays with a single-byte length prefix before each item. Because the prefix is one byte, each item can be at most 255 bytes; the helper raises ValueError when a component exceeds that, since it could not be encoded without corrupting the key framing.","triggerScenarios":"Calling key_for_account(address), key_for_fee_params(), or key_for_fee_pool() with a component longer than 255 bytes — e.g. a malformed 256+ byte address, or an accidentally serialized protobuf blob passed where a raw short key component is expected.","commonSituations":"Passing a serialized protobuf message instead of raw address bytes to key_for_account; a corrupted or truncated state read yielding oversized byte strings; custom plugin code that invents new key components from unbounded user input (long memos, URLs).","solutions":["Inspect the oversized item at the call site (print len(item)) and determine which component is unexpectedly long; fix the upstream producer to pass raw, bounded bytes (e.g. a 20/32-byte address).","If the item is a serialized protobuf, pass the inner field (e.g. msg.address bytes) rather than the full serialized message.","Validate length at your own boundary before calling: assert len(component) <= 255, and reject or hash over-long user-supplied components.","If a legitimately larger key space is needed, hash the component (e.g. sha256) to a fixed 32 bytes before joining, or change the prefix scheme deliberately."],"exampleFix":"// before\nkey = key_for_account(serialized_account_msg)  # >255 bytes -> ValueError\n// after\nkey = key_for_account(msg.from_address)  # raw address bytes, <=255","handlingStrategy":"validation","validationCode":"def assert_short(b: bytes, name: str) -> bytes:\n    if not isinstance(b, (bytes, bytearray)) or len(b) > 255:\n        raise ValueError(f\"{name} must be <=255 bytes, got {len(b) if b else type(b)}\")\n    return bytes(b)\n\nkey = key_for_account(assert_short(addr, 'address'))","typeGuard":"def is_key_component(b) -> bool:\n    return isinstance(b, (bytes, bytearray)) and 0 < len(b) <= 255","tryCatchPattern":"try:\n    key = key_for_account(addr)\nexcept ValueError as e:\n    if 'Item too long' in str(e):\n        logger.error('oversized key component: %s', e)\n        return reject_tx()\n    raise","preventionTips":["Pass raw protobuf field bytes (addresses), never whole serialized messages.","Bound user-supplied key inputs; hash anything potentially longer than 255 bytes.","Add a unit test asserting key lengths for every key helper.","Keep key components to fixed-size fields (20/32-byte addresses, 8-byte ints)."],"tags":["python","validation","state-keys","length-prefix"],"backgroundTag":"value-out-of-range","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}