reflex-dev/reflex · error · ValueError

Invalid data type {type(data)} for download. Use `str` or `b

Error message

Invalid data type {type(data)} for download. Use `str` or `bytes`.

What it means

The data argument of rx.download must be str or bytes so it can be base64-encoded into a data: URI; other types (int, dict, numpy arrays, objects) cannot be encoded.

Source

Thrown at packages/reflex-base/src/reflex_base/event/__init__.py:1776

            is_data_url = (data.js_type() == "string") & (
                data.to(str).startswith("data:")
            )

            # If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI.
            url = cond(
                is_data_url,
                data.to(str),
                f"data:{mime_type}," + data.to_string(),
            )
        elif isinstance(data, bytes):
            if mime_type is None:
                mime_type = "application/octet-stream"
            # Caller provided bytes, so base64 encode it as a data: URI.
            b64_data = b64encode(data).decode("utf-8")
            url = f"data:{mime_type};base64," + b64_data
        else:
            msg = f"Invalid data type {type(data)} for download. Use `str` or `bytes`."
            raise ValueError(msg)

    return server_side(
        "_download",
        inspect.signature(download),
        url=url,
        filename=filename,
    )


def call_script(
    javascript_code: str | Var[str],
    callback: "EventType[Any] | None" = None,
) -> EventSpec:
    """Create an event handler that executes arbitrary javascript code.

    Args:
        javascript_code: The code to execute.
        callback: EventHandler that will receive the result of evaluating the javascript code.

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Encode as str/bytes: str(value).encode() or json.dumps(dict).encode()
  2. For a Path, read it first: data=path.read_bytes()
  3. For text, pass the str directly (mime_type defaults to text/plain)

Example fix

# before
rx.download(data={'a': 1})
# after
import json
rx.download(data=json.dumps({'a': 1}), filename='data.json')
Defensive patterns

Strategy: type-guard

Validate before calling

def ok_download_data(d) -> bool:
    return d is None or isinstance(d, (str, bytes))

Type guard

def is_download_data(d) -> TypeGuard[str | bytes | None]: return d is None or isinstance(d, (str, bytes))

Prevention

When it happens

Trigger: rx.download(data=123), rx.download(data={'a': 1}), or passing a Path/bytearray/object.

Common situations: Passing a JSON dict expecting it to be serialized, or a pathlib.Path instead of its contents; numeric data from computations.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28). Data as JSON: /api/errors/69916d8e8053b8dc. Report an issue: GitHub.