All Posts programming Fixing Syncthing’s REST API: Why “application/json; charset=utf-8” Was Wrong and How a Simple Commit Made It Right

Fixing Syncthing’s REST API: Why “application/json; charset=utf-8” Was Wrong and How a Simple Commit Made It Right

· 841 words · 4 minute read
Go in production: interesting moments ▹

Syncthing is the reliable, open-source tool that keeps your files in sync across computers, phones, and servers without a central cloud. One of its most useful features is the built-in REST API — a clean, JSON-based interface that lets you check status, change settings, or build your own tools and scripts.

But in late 2025, a small standards-compliance bug surfaced in that API. It didn’t break anything for most users, yet it was technically incorrect. Here’s the full story — explained simply, with the exact code changes, why they mattered, and how the fix was shipped.

The Problem: An Extra “; charset=utf-8” That Shouldn’t Be There 🔗

When you asked the Syncthing REST API for JSON data (e.g. /rest/noauth/health or any /rest/... endpoint), the server replied with this header:

Content-Type: application/json; charset=utf-8

That looks harmless. JSON is text, and UTF-8 is the standard encoding, right?

Not quite.

According to the official rules:

  • The IANA media-type registration for application/json explicitly says: no parameters (including charset) are defined.
  • RFC 8259 (the JSON spec) states that JSON in open systems must be UTF-8, and clients are required to assume UTF-8. Adding a charset parameter is redundant and non-standard.

In practice, almost every browser and HTTP library ignored the extra part. But strict API validators, some proxies, future tools, or security scanners could flag it as non-compliant. The bug report (#10500) showed a clear curl --verbose example that proved the header was being sent everywhere JSON was returned.

Why did Syncthing add it in the first place?
Older Go code (and many tutorials) used to write application/json; charset=utf-8 out of habit, even though the JSON RFC made it unnecessary. Over time it became baked into Syncthing’s API handlers.

The Fix: One Targeted Change, Two Commits, Zero Drama 🔗

On December 28, 2025, contributor prathik8794 opened PR #10508 with the perfect title:
“chore(api): remove charset declaration from JSON content-type (fixes #10500)”

The goals were crystal-clear from the start:

  1. Make every JSON response standards-compliant by using exactly application/json.
  2. Keep everything else unchanged — no behavior change for users, no performance impact, no new dependencies.
  3. Ship it quickly so the next Syncthing release would be clean.

The Commits That Delivered the Fix 🔗

Commit 1 (b5a4be9 – Dec 28, 2025)
Message: updated content-type to application/json (fixes syncthing#10500)

This was the heart of the fix. In lib/api/api.go (the file that powers all REST endpoints), the code that set the response header was updated.

Before (incorrect):

w.Header().Set("Content-Type", "application/json; charset=utf-8")

After (correct):

w.Header().Set("Content-Type", "application/json")

That single line change affected every JSON endpoint at once because the API code re-uses the same header-setting pattern (or helper) throughout. No other files needed touching.

Commits 2 & 3 (a69c981 and 952c301 – Dec 29, 2025)
These were simple “Merge branch ‘main’ into main” commits to keep the PR up-to-date with the latest main branch before merging. They show good hygiene — the contributor made sure the fix was based on the freshest code.

Final merge commit (50fe005 – Dec 29, 2025)
Maintainer calmh reviewed the PR, renamed the title for better changelog style, approved it, and merged via squash. The issue was automatically closed as “completed”.

What the Fix Looks Like in Action 🔗

Before the fix (old curl output):

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
...
{"status": "OK"}

After the fix (current behavior):

HTTP/1.1 200 OK
Content-Type: application/json
...
{"status": "OK"}

The JSON body is identical. UTF-8 is still used — it’s just no longer spelled out in the header (exactly as the spec requires).

Why This Matters (Even Though It Was “Just a Header”) 🔗

  • Standards compliance → Future tools and linters won’t complain.
  • Cleaner API → Matches how modern JSON services (GitHub, Stripe, etc.) behave.
  • Zero risk → The change is purely declarative; Go’s JSON marshaler already outputs UTF-8.
  • Maintainability → One less quirky detail for new contributors to wonder about.

The Result: Goal Achieved ✅ 🔗

By the end of December 29, 2025:

  • Issue #10500 was closed.
  • The change landed in main.
  • It shipped in Syncthing v2.0.14 (and all later releases).
  • Every JSON response from the REST API now follows the official specification.

No users noticed anything different — which is exactly how a great fix should feel.

Try It Yourself 🔗

If you run the latest Syncthing, just open a terminal and run:

curl -v http://localhost:8384/rest/noauth/health

You’ll see the clean Content-Type: application/json header — proof that the fix is live.


Thanks to Prathik P Kulkarni for the precise patch and to the Syncthing team for the rapid review. Small standards fixes like this keep the project professional and future-proof.

If you’re building tools on top of Syncthing’s REST API, you can now rely on the header being exactly what the spec promises. Happy syncing! 🚀

I hope you enjoyed reading this post as much as I enjoyed writing it. If you know a person who can benefit from this information, send them a link of this post. If you want to get notified about new posts, follow me on YouTube , Twitter (x) , LinkedIn , and GitHub .

Go in production: interesting moments ▹