redis/redis-py · error · ValueError

Provide either json_body or data, not both.

Error message

Provide either json_body or data, not both.

What it means

_prepare_body (redis/http/http_client.py:356) raises ValueError when both json_body and data are supplied to a POST/PUT/PATCH. The two parameters are mutually exclusive: json_body is serialized to compact JSON, data is sent as raw bytes/str. Accepting both would make the on-wire body ambiguous, so the client refuses rather than guess.

Solutions

  1. Pass exactly one of json_body (for JSON) or data (for raw bytes/str).
  2. If you have a dict, prefer json_body; if you have pre-serialized bytes, use data.
  3. In wrapper functions, normalize to one form before calling HttpClient and drop the other.

Example fix

// before
http.post('/items', json_body=payload, data=json.dumps(payload))
// after
http.post('/items', json_body=payload)
Defensive patterns

Strategy: validation

Validate before calling

assert (json_body is None) or (data is None), 'pass json_body or data, not both'

Type guard

def exactly_one_body(json_body, data) -> bool:
    return (json_body is not None) ^ (data is not None) or (json_body is None and data is None)

Prevention

When it happens

Trigger: Calling http.post(path, json_body={'a': 1}, data=b'raw') ; passing both because a wrapper forwards a generic payload dict alongside a pre-serialized body; mixing the JSON helper with a manual bytes body.

Common situations: A generic request helper that accepts both forms and forgets to clear one; refactoring from data= to json_body= and leaving the old argument in place; copy-paste between calls.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/586bea9a7db4362d. Report an issue: GitHub.

Appendix: source

Thrown at redis/http/http_client.py:356

        resp = self.request(
            method=method,
            path=path,
            params=params,
            headers=headers,
            body=body,
            timeout=timeout,
        )
        if not (200 <= resp.status < 400):
            raise HttpError(resp.status, resp.url, resp.text())
        if expect_json:
            return resp.json()
        return resp

    def _prepare_body(
        self, json_body: Optional[Any] = None, data: Optional[Union[bytes, str]] = None
    ) -> Optional[Union[bytes, str]]:
        if json_body is not None and data is not None:
            raise ValueError("Provide either json_body or data, not both.")
        if json_body is not None:
            return json.dumps(json_body, ensure_ascii=False, separators=(",", ":"))
        return data

    def _build_url(
        self,
        path: str,
        params: Optional[
            Mapping[str, Union[None, str, int, float, bool, list, tuple]]
        ] = None,
    ) -> str:
        url = urljoin(self.base_url or "", path)
        if params:
            # urlencode with doseq=True supports list/tuple values
            query = urlencode(
                {k: v for k, v in params.items() if v is not None}, doseq=True
            )
            separator = "&" if ("?" in url) else "?"

View on GitHub (pinned to 6a6b581b48)