canopy-network/canopy · error · ValueError

Item too long: bytes (max 255)

Error message

Item too long: {len(item)} bytes (max 255)

What it means

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.

Solutions

  1. 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).
  2. If the item is a serialized protobuf, pass the inner field (e.g. msg.address bytes) rather than the full serialized message.
  3. Validate length at your own boundary before calling: assert len(component) <= 255, and reject or hash over-long user-supplied components.
  4. 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.

Example fix

// before
key = key_for_account(serialized_account_msg)  # >255 bytes -> ValueError
// after
key = key_for_account(msg.from_address)  # raw address bytes, <=255
Defensive patterns

Strategy: validation

Validate before calling

def assert_short(b: bytes, name: str) -> bytes:
    if not isinstance(b, (bytes, bytearray)) or len(b) > 255:
        raise ValueError(f"{name} must be <=255 bytes, got {len(b) if b else type(b)}")
    return bytes(b)

key = key_for_account(assert_short(addr, 'address'))

Type guard

def is_key_component(b) -> bool:
    return isinstance(b, (bytes, bytearray)) and 0 < len(b) <= 255

Try / catch

try:
    key = key_for_account(addr)
except ValueError as e:
    if 'Item too long' in str(e):
        logger.error('oversized key component: %s', e)
        return reject_tx()
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06). Data as JSON: /api/errors/b4e77e3c5795aa4d. Report an issue: GitHub.

Appendix: source

Thrown at plugin/python/contract/contract.py:90

}


# State key prefixes (matching Go)
ACCOUNT_PREFIX = b"\x01"
POOL_PREFIX = b"\x02"
PARAMS_PREFIX = b"\x07"


# Key generation functions (from keys.py)

def join_len_prefix(*items: Optional[bytes]) -> bytes:
    """Join byte arrays with length prefixes."""
    result = bytearray()
    for item in items:
        if not item:
            continue
        if len(item) > 255:
            raise ValueError(f"Item too long: {len(item)} bytes (max 255)")
        result.append(len(item))
        result.extend(item)
    return bytes(result)


def format_uint64(value: Union[int, str]) -> bytes:
    """Format uint64 as big-endian bytes."""
    if isinstance(value, str):
        value = int(value)
    if not isinstance(value, int) or value < 0 or value >= (1 << 64):
        raise ValueError(f"Invalid uint64 value: {value}")
    return struct.pack('>Q', value)


def key_for_account(address: bytes) -> bytes:
    """Generate state database key for an account."""
    return join_len_prefix(ACCOUNT_PREFIX, address)

View on GitHub (pinned to ee8197d91d)