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
- Pass exactly one of json_body (for JSON) or data (for raw bytes/str).
- If you have a dict, prefer json_body; if you have pre-serialized bytes, use data.
- 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
- Pass json_body for JSON payloads, data for raw bytes/str — never both.
- In wrappers, normalize to one form before calling HttpClient.
- When migrating from data= to json_body=, remove the old argument.
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
- ACL LOG count must be an integer
- bit must be 0 or 1
- Both start and end must be specified
- ``byfloat`` and ``byint`` are mutually exclusive.
- Cache must implement CacheInterface
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)