openai/openai-python · error · RuntimeError

Could not read bytes from {data}; Received {type(binary)}

Error message

Could not read bytes from {data}; Received {type(binary)}

What it means

When a request body field is typed as a file/upload, the SDK calls .read() on the object and base64-encodes the result for JSON transport. This RuntimeError means the object's read() returned something that is neither bytes nor a str (e.g. a memoryview, bytearray consumed incorrectly, or a custom file-like object returning a generator). The sync transform could not produce bytes to encode, so serialization of the request body fails before sending.

Source

Thrown at src/openai/_utils/_transform.py:256

        if format_ == "iso8601":
            return data.isoformat()

        if format_ == "custom" and format_template is not None:
            return data.strftime(format_template)

    if format_ == "base64" and is_base64_file_input(data):
        binary: str | bytes | None = None

        if isinstance(data, pathlib.Path):
            binary = data.read_bytes()
        elif isinstance(data, io.IOBase):
            binary = data.read()

            if isinstance(binary, str):  # type: ignore[unreachable]
                binary = binary.encode()

        if not isinstance(binary, bytes):
            raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}")

        return base64.b64encode(binary).decode("ascii")

    return data


def _transform_typeddict(
    data: Mapping[str, object],
    expected_type: type,
) -> Mapping[str, object]:
    result: dict[str, object] = {}
    annotations = get_type_hints(expected_type, include_extras=True)
    for key, value in data.items():
        if not is_given(value):
            # we don't need to include omitted values here as they'll
            # be stripped out before the request is sent anyway
            continue

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. Ensure the object passed for the file field has read() returning bytes (encode str results)
  2. Wrap custom streams: read = lambda *a: raw.read() or return bytes(memoryview_chunk) from read()
  3. Pass raw bytes or a real file object opened in binary mode ('rb')
  4. Add a unit test asserting your upload object's read() returns bytes

Example fix

# before
class WeirdFile:
    def read(self): return memoryview(b"data")
client.models.create(file=WeirdFile())

# after
class BytesFile:
    def read(self, *a): return b"data"
client.models.create(file=BytesFile())
Defensive patterns

Strategy: type-guard

Validate before calling

data = f.read() if hasattr(f, "read") else f
assert isinstance(data, (bytes, bytearray)), type(data)

Type guard

def is_bytes_readable(obj: object) -> bool:
    return isinstance(obj, (bytes, bytearray)) or (hasattr(obj, "read") and isinstance(getattr(obj, "read")(), (bytes, type(None))))

Try / catch

try:
    client.models.create(file=f)
except RuntimeError as e:
    raise ValueError("file must read() bytes") from e

Prevention

When it happens

Trigger: Passing a custom file-like object whose read() returns a non-bytes value; passing a SpooledTemporaryFile wrapper or object wrapping bytes in memoryview; constructing models locally with an improper upload object and then serializing them.

Common situations: Custom IO abstractions (e.g. adapters around cloud storage streams) not returning bytes; wrapping files in classes that return the underlying buffer object; upgrading SDK versions where upload handling moved to the transform layer.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/aed2a055773cf669. Report an issue: GitHub.