-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Description
The SDK sends Content-Type: application/json header even when no body is present (e.g., POST requests with no payload). This causes servers with JSON body parsers to fail because an empty string is not valid JSON.
Reproduction
Any POST/PUT/PATCH endpoint that doesn't require a request body:
from opencode_ai import AsyncOpencode
client = AsyncOpencode(base_url="http://localhost:3456")
await client.session.create() # No body parametersHTTP Request Sent
POST /session HTTP/1.1
Host: localhost:3456
Content-Length: 0
Content-Type: application/json
Accept: application/json
...Server Response
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{"name":"UnknownError","data":{"message":"Error: Malformed JSON in request body\n at <anonymous> (../../node_modules/.bun/hono@4.10.7/node_modules/hono/dist/validator/validator.js:21:21)\n at processTicksAndRejections (native:7:39)"}}The server sees Content-Type: application/json, attempts to parse the body as JSON, but fails because the body is empty.
Expected Behavior
When no body content is provided, the SDK should not send Content-Type: application/json. The header should only be present when there's actual JSON content to parse.
POST /session HTTP/1.1
Host: localhost:3456
Content-Length: 0
Accept: application/jsonRoot Cause
In _base_client.py, the default_headers property unconditionally includes Content-Type: application/json:
@property
def default_headers(self) -> dict[str, str | Omit]:
return {
"Accept": "application/json",
"Content-Type": "application/json", # Always set
...
}The _build_request method only removes this header for GET requests:
is_body_allowed = options.method.lower() != "get"
if is_body_allowed:
if isinstance(json_data, bytes):
kwargs["content"] = json_data
else:
kwargs["json"] = json_data if is_given(json_data) else None
kwargs["files"] = files
else:
headers.pop("Content-Type", None) # Only removed for GETProposed Fix
Also remove Content-Type when the body is empty for non-GET requests:
if is_body_allowed:
if isinstance(json_data, bytes):
kwargs["content"] = json_data
else:
kwargs["json"] = json_data if is_given(json_data) else None
kwargs["files"] = files
# Remove Content-Type if there's no actual body content
has_body = isinstance(json_data, bytes) or is_given(json_data) or files
if not has_body:
headers.pop("Content-Type", None)
else:
headers.pop("Content-Type", None)Workaround
Users can manually omit the header:
from opencode_ai import Omit
await client.session.create(extra_headers={"Content-Type": Omit()})But this shouldn't be necessary for standard API usage.
Environment
- SDK: Stainless-generated Python client
- Python: 3.13.2
- Server: Hono (Node.js) with JSON body validation