{"record":{"id":"6443f8b04c0133c8","repo":"Textualize/textual","slug":"must-be-bytes","errorCode":null,"errorMessage":"must be bytes","messagePattern":"must be bytes","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/textual/_binary_encode.py","lineNumber":182,"sourceCode":"        return decoder(datum)\n\n    return encode(data)\n\n\ndef load(encoded: bytes) -> object:\n    \"\"\"Load an encoded data structure from bytes.\n\n    Args:\n        encoded: Encoded data in bytes.\n\n    Raises:\n        DecodeError: If an error was encountered decoding the string.\n\n    Returns:\n        Decoded data.\n    \"\"\"\n    if not isinstance(encoded, bytes):\n        raise TypeError(\"must be bytes\")\n    max_position = len(encoded)\n    position = 0\n\n    def get_byte() -> bytes:\n        \"\"\"Get an encoded byte and advance position.\n\n        Raises:\n            DecodeError: If the end of the data was reached\n\n        Returns:\n            A bytes object with a single byte.\n        \"\"\"\n        nonlocal position\n        if position >= max_position:\n            raise DecodeError(\"More data expected\")\n        character = encoded[position : position + 1]\n        position += 1\n        return character","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/_binary_encode.py#L164-L200","documentation":"load() in textual._binary_encode expects the wire format to be bytes and rejects anything else with TypeError('must be bytes') before decoding starts. This is a strict input-type contract for the internal binary protocol.","triggerScenarios":"Calling load() with a str (e.g. a decoded string from a socket), a bytearray, memoryview, or None instead of bytes.","commonSituations":"Reading data from a transport that yields str (text-mode files, WebSocket text frames) and passing it directly; test code passing string literals; accidentally double-decoding an already-decoded payload.","solutions":["Encode the input to bytes first: load(data.encode('utf-8')) only if it was wrongly decoded, otherwise pass the raw bytes","Read sockets/files in binary mode so you receive bytes","If you have a bytearray/memoryview, wrap with bytes() before calling load","Verify you are not passing an already-decoded Python object"],"exampleFix":"# before\nload('{\"a\": 1}')  # TypeError: must be bytes\n\n# after\nload(b'\\x00\\x01...')  # raw encoded bytes","handlingStrategy":"type-guard","validationCode":"if not isinstance(payload, (bytes, bytearray)):\n    payload = bytes(payload, 'utf-8')  # or raise early with context\nload(payload)","typeGuard":"def is_encoded_bytes(data: object) -> bool:\n    return isinstance(data, (bytes, bytearray)) and not isinstance(data, str)","tryCatchPattern":"try:\n    load(payload)\nexcept TypeError as e:\n    if 'must be bytes' in str(e):\n        load(payload.encode('utf-8'))\n    raise","preventionTips":["Open files/sockets in binary mode","Convert bytearray/memoryview with bytes() before load","Never pass str from text-mode transports directly"],"tags":["python","textual","serialization","type-mismatch","internal-api"],"backgroundTag":"wrong-argument-type-bytes-expected","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}