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 by ClientSession.request when both data and json are not None. The two arguments imply mutually exclusive body encodings: data is form/stream-oriented, json is serialized with the configured serializer. Allowing both would leave the actual body undefined.
Solutions
- Pick one body form: json=obj for JSON APIs, data=... for forms or raw bodies.
- If you need JSON inside multipart/form fields, build a FormData and embed the JSON as one field instead of using the json kwarg.
- Audit wrapper functions to ensure only one of data/json is forwarded.
Example fix
// before
await session.post(url, data=form, json={'a': 1})
// after
await session.post(url, json={'a': 1}) Defensive patterns
Strategy: validation
Validate before calling
def exactly_one_of(**kwargs):
present = [k for k, v in kwargs.items() if v is not None]
if len(present) > 1:
raise ValueError(f'only one of {list(kwargs)} may be set, got {present}')
# usage:
exactly_one_of(data=data, json=json)
await session.post(url, data=data, json=json) Type guard
def has_unique_body(data, json_) -> bool:
return not (data is not None and json_ is not None) Try / catch
try:
resp = await session.post(url, data=data, json=json_)
except ValueError as e:
if 'data and json' in str(e):
# pick one body form
resp = await session.post(url, json=json_)
else:
raise Prevention
- In wrapper functions, accept either data or json explicitly, not both via **kwargs.
- Add a pre-call assertion that exactly one body argument is set.
- Document request helpers with the chosen body convention.
When it happens
Trigger: Calling session.post(url, data=payload, json=obj). Also fires when one of them is set to a falsy-but-not-None value (e.g. {} or []) combined with the other, since the check is 'is not None'.
Common situations: Refactoring a call that sent form data and tacking on json without removing data. Helper functions that accept **kwargs and forward both. Copy-pasting snippets that each contribute one of the two kwargs.
Related errors
- 1007
- A ":" is not allowed in login (RFC 7617#section-2)
- A ":" is not allowed in username (RFC 1945#section-11.1)
- bad content disposition parameter
- bad content disposition type
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/cb6943a5f34d4233.
Report an issue: GitHub.
Appendix: 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 d041d4d0fd)