sgl-project/sglang · error · ValueError

Expected base64-encoded bytes

Error message

Expected base64-encoded bytes

What it means

msgspec_utils' _decode_value expects string fields to be base64-encoded bytes and decodes them with strict validation. A string containing characters outside the base64 alphabet (or bad padding) raises ValueError('Expected base64-encoded bytes'). Lists/tuples are decoded recursively, so a nested bad string also triggers it.

Source

Thrown at python/sglang/srt/utils/msgspec_utils.py:27

from pydantic_core import core_schema


class Base64Bytes:
    """Pydantic marker for HTTP JSON base64-encoded bytes fields."""

    def __get_pydantic_core_schema__(self, source_type: Any, handler):
        return core_schema.no_info_before_validator_function(
            self._decode_value,
            handler(source_type),
        )

    @classmethod
    def _decode_value(cls, value: Any) -> Any:
        if isinstance(value, str):
            try:
                return base64.b64decode(value, validate=True)
            except binascii.Error as exc:
                raise ValueError("Expected base64-encoded bytes") from exc

        if isinstance(value, list):
            return [cls._decode_value(item) for item in value]

        if isinstance(value, tuple):
            return tuple(cls._decode_value(item) for item in value)

        return value


def msgspec_to_builtins(obj: Any) -> Any:
    """Recursively convert msgspec structs and dataclasses to builtins."""
    if isinstance(obj, msgspec.Struct):
        return {
            field.name: msgspec_to_builtins(getattr(obj, field.name))
            for field in msgspec.structs.fields(type(obj))
        }

View on GitHub (pinned to 0132848349)

Solutions

  1. base64-encode byte fields on the producer side: base64.b64encode(b).decode().
  2. If the field is genuinely text, move it to a non-bytes field in the schema so _decode_value never touches it.
  3. For debugging, catch binascii.Error context to identify which field failed.

Example fix

# before
msg = {"payload": "hello world"}   # not valid base64 (space)

# after
import base64
msg = {"payload": base64.b64encode(b"hello world").decode()}
Defensive patterns

Strategy: validation

Validate before calling

import base64, binascii
try:
    base64.b64decode(s, validate=True)
except (binascii.Error, ValueError):
    raise ValueError(f"field is not base64: {s!r}")

Type guard

import base64

def is_base64_str(s: str) -> bool:
    try:
        base64.b64decode(s, validate=True)
        return True
    except Exception:
        return False

Prevention

When it happens

Trigger: Decoding a msgspec/json payload where a field intended to be base64 bytes actually holds free-form text — e.g., a filename, UUID with dashes is fine but a URL/path with ':' or '/' is not.

Common situations: Schema drift: a field changed from plain string to bytes-encoded and old payloads are replayed; or a caller puts a human-readable string where the wire format requires base64.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/91ee3ee955a53547. Report an issue: GitHub.