Skip to content

fix(http): don't force application/json on multipart uploads - #11

Merged
senamakel merged 1 commit into
mainfrom
fix/multipart-content-type
Aug 4, 2026
Merged

fix(http): don't force application/json on multipart uploads#11
senamakel merged 1 commit into
mainfrom
fix/multipart-content-type

Conversation

@graycyrus

@graycyrus graycyrus commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

RawClient::headers() sets a fixed Content-Type: application/json on every request. On post_multipart that overrode the multipart/form-data; boundary=… reqwest's .multipart(form) must set, so the backend JSON-parsed the multipart body and returned 500 "Unexpected token '-', \"--<boundary>\"... is not valid JSON". This broke all file uploads (OpenHuman storage_upload_file + the whole file→attachment chain).

Fix

Strip Content-Type in post_multipart before .multipart(form) so reqwest owns the multipart content-type. Scoped to the multipart path — every other verb is byte-identical, including body-less POSTs (teams, payments/stripe/portal, auth, channels) that rely on the shared application/json. (A cleaner refactor would move content-type entirely to the body methods, but that would drop the json type from those body-less POSTs — deferred to avoid regressions.)

Proof

Live against the (now-healthy) backend: a plain multipart curl → 200; the identical body with a forced Content-Type: application/json → the exact 500. Masked until now by the separately-fixed storage-bucket 500.

Tests

tests/multipart.rs (wiremock): asserts post_multipart sends a multipart/form-data content-type and NOT application/json, plus a no-regression check that a JSON POST still sends application/json. Full suite green.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed multipart uploads to send the correct multipart/form-data content type, including the required boundary.
    • Preserved application/json handling for standard JSON requests.
    • Improved reliability of multipart response processing.

The shared header builder sets a fixed Content-Type: application/json, which
overrode the multipart/form-data boundary reqwest's .multipart(form) sets, so
the backend JSON-parsed the multipart body and 500'd ("Unexpected token '-',
"--<boundary>"... is not valid JSON"). Strip Content-Type in post_multipart so
.multipart() owns it; every other verb (incl. body-less POSTs that rely on the
json content-type) is untouched. + wiremock regression tests.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

graycyrus has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

HttpClient::post_multipart now removes the shared JSON Content-Type header before sending multipart data. Tests verify multipart headers and confirm that regular JSON POST requests remain unchanged.

Changes

Multipart request handling

Layer / File(s) Summary
Header handling and regression coverage
src/lib.rs, tests/multipart.rs
post_multipart removes the JSON Content-Type header before applying multipart data. Tests verify the multipart content type, response parsing, and unchanged JSON POST behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • tinyhumansai/sdk#8 — Directly addresses the duplicate JSON and multipart Content-Type problem in post_multipart.

Poem

A rabbit packed a form with care,
And sent it through the boundary air.
JSON stayed on its proper track,
Multipart headers no longer clash.
Hop, hop—clean requests arrive!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the multipart upload content-type fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/multipart.rs (1)

59-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Complete the header-regression coverage.

Line 60 accepts multipart/form-data without a boundary= parameter. Assert the boundary parameter because the server needs it to parse the form.

Lines 83-106 send a JSON body. .json() can set application/json independently. Add a body-less RawClient::send(Method::POST, ..., None, ...) test that asserts application/json. This covers the preserved contract stated for body-less POST requests.

Also applies to: 83-106

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/multipart.rs` around lines 59 - 66, Extend the multipart header
assertions near the existing content_type checks to require a boundary=
parameter in the multipart/form-data value. In the body-less POST coverage
around the JSON request in the test flow, add a RawClient::send(Method::POST,
..., None, ...) request and assert its response Content-Type is
application/json, preserving the existing multipart and JSON-body assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/multipart.rs`:
- Around line 59-66: Extend the multipart header assertions near the existing
content_type checks to require a boundary= parameter in the multipart/form-data
value. In the body-less POST coverage around the JSON request in the test flow,
add a RawClient::send(Method::POST, ..., None, ...) request and assert its
response Content-Type is application/json, preserving the existing multipart and
JSON-body assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee72cddd-3ec3-409a-bf07-2df995f5f9d0

📥 Commits

Reviewing files that changed from the base of the PR and between 495be81 and a2f26f4.

📒 Files selected for processing (2)
  • src/lib.rs
  • tests/multipart.rs

@graycyrus
graycyrus requested a review from senamakel August 4, 2026 10:35
@senamakel
senamakel merged commit 23a2f6e into main Aug 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants