aio-libs/aiohttp · error · ValueError
data and json parameters can not be used at the same time
Error message
data and json parameters can not be used at the same time
What it means
Raised in `_request` (client.py:515-518) when both `data` and `json` are non-None on the same call. aiohttp needs to choose one body encoding strategy — `json=` wraps the value in `JsonPayload` (or `JsonBytesPayload`), while `data=` is for form/stream/raw bodies — and the two are mutually exclusive. The guard short-circuits before any payload is built.
Source
Thrown at aiohttp/client.py:516
# NOTE: timeout clamps existing connect and read timeouts. We cannot
# set the default to None because we need to detect if the user wants
# to use the existing timeouts by setting timeout to None.
if self.closed:
raise RuntimeError("Session is closed")
method = method.upper()
if ssl is sentinel:
ssl = self._default_ssl
if not isinstance(ssl, SSL_ALLOWED_TYPES):
raise TypeError(
"ssl should be SSLContext, Fingerprint, or bool, "
f"got {ssl!r} instead."
)
if data is not None and json is not None:
raise ValueError(
"data and json parameters can not be used at the same time"
)
elif json is not None:
if self._json_serialize_bytes is not None:
data = payload.JsonBytesPayload(json, dumps=self._json_serialize_bytes)
else:
data = payload.JsonPayload(json, dumps=self._json_serialize)
redirects = 0
history: list[ClientResponse] = []
version = self._version
params = params or {}
# Merge with default headers and transform to CIMultiDict
headers = self._prepare_headers(headers)
try:
url = self._build_url(str_or_url)View on GitHub (pinned to c0ef574e29)
Solutions
- Pick one: pass the payload as `json=payload` for JSON, or `data=payload` for form/raw.
- In forwarding helpers, explicitly pop the unused one: `kwargs.pop('data', None) if 'json' in kwargs else None`.
- Use `aiohttp.payload.JsonPayload(obj)` explicitly if you need to send it via `data=` for unusual cases.
Example fix
// before await session.post(url, data=form, json=payload) // after await session.post(url, json=payload) # JSON body // or await session.post(url, data=form) # form / raw body
Defensive patterns
Strategy: validation
Validate before calling
def build_kwargs(kwargs):
if kwargs.get('data') is not None and kwargs.get('json') is not None:
raise ValueError('pass either data= or json=, not both')
return kwargs Try / catch
try:
await session.post(url, **kwargs)
except ValueError as e:
if 'data and json' in str(e):
kwargs.pop('data', None) # keep json
await session.post(url, **kwargs)
else:
raise Prevention
- Make forwarding helpers choose one body kwarg explicitly.
- In wrapper functions, pop the unused alternative before delegating.
- Add a unit test that asserts your helper rejects both-set calls.
When it happens
Trigger: Calling `session.post(url, data=some_dict, json=some_other_dict)`, or forwarding a request helper that always sets both kwargs (e.g., `**kwargs` merged with a default `json=`).
Common situations: Refactoring a helper that previously took `data=` to also support `json=` and forgetting to make them exclusive; merging per-call overrides onto default kwargs via dict update that leaves both populated; OpenAPI-generated clients populating both fields.
Related errors
- base_url must have a trailing '/'
- timeout parameter cannot be of {type} type, please use 'time
- Inheritance class {cls} from ClientSession is forbidden
- Cannot follow redirect with a consumed request body. Use byt
- None is not allowed as login value
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/cb6943a5f34d4233.json.
Report an issue: GitHub.