Summary
When using elide serve with a fetch handler that returns a Response with a custom Content-Type header, the header is overwritten based on the body type, ignoring the user-specified value.
Regression Source
This bug was introduced in PR #1736 ("feat: new server engine", merged Nov 8, 2025).
The mapResponseBody() function was added as part of the new server engine, and it unconditionally overwrites Content-Type:
// From PR #1736 diff - packages/graalvm/.../FetchIntrinsic.kt
+ private fun mapResponseBody(
+ value: Value?,
+ headers: FetchMutableHeaders,
+ ...
+ value.isString -> {
+ val bytes = value.asString().toByteArray(StandardCharsets.UTF_8)
+ headers.set("Content-Type", "text/plain") // ← Bug: unconditionally overwrites
The new fetch handler pattern's body mapping logic doesn't respect user-specified headers.
Expected Behavior
export default async function fetch(request: Request) {
return new Response("<h1>Hello</h1>", {
headers: { "Content-Type": "text/html; charset=utf-8" }
});
}
Should return Content-Type: text/html; charset=utf-8
Actual Behavior
Returns Content-Type: text/plain because mapResponseBody() unconditionally overwrites the header.
Root Cause
In FetchIntrinsic.kt, the mapResponseBody() function always calls headers.set("Content-Type", ...) based on body type:
- String body →
text/plain
- Buffer →
application/octet-stream
- Object →
application/json
This overwrites any user-specified Content-Type because headers are passed to mapResponseBody() after being populated from user options, and then overwritten.
Proposed Fix
Check if Content-Type is already set before overwriting:
// Before (bug):
headers.set("Content-Type", "text/plain")
// After (fix):
if (!headers.has("Content-Type")) headers.set("Content-Type", "text/plain")
Verification
Confirmed via curl that custom headers ARE applied but Content-Type is overwritten:
< X-Custom: test-value ← Works!
< Content-Type: text/plain ← Overwritten (should be text/html)
Affected Versions
Testing revealed:
- beta9: Fetch handler pattern not yet available (server doesn't start)
- beta10, beta11-rc1 through rc3: Have fetch handler but with Content-Type bug
Since PR #1736 introduced both the fetch handler pattern AND the mapResponseBody() function, all versions with fetch handler support have this bug.
No Workaround Available
Environment
- Elide version: 1.0.0-beta11-rc3
- OS: Linux
- Runtime: Native
Summary
When using
elide servewith a fetch handler that returns aResponsewith a customContent-Typeheader, the header is overwritten based on the body type, ignoring the user-specified value.Regression Source
This bug was introduced in PR #1736 ("feat: new server engine", merged Nov 8, 2025).
The
mapResponseBody()function was added as part of the new server engine, and it unconditionally overwritesContent-Type:The new fetch handler pattern's body mapping logic doesn't respect user-specified headers.
Expected Behavior
Should return
Content-Type: text/html; charset=utf-8Actual Behavior
Returns
Content-Type: text/plainbecausemapResponseBody()unconditionally overwrites the header.Root Cause
In
FetchIntrinsic.kt, themapResponseBody()function always callsheaders.set("Content-Type", ...)based on body type:text/plainapplication/octet-streamapplication/jsonThis overwrites any user-specified Content-Type because headers are passed to
mapResponseBody()after being populated from user options, and then overwritten.Proposed Fix
Check if Content-Type is already set before overwriting:
Verification
Confirmed via curl that custom headers ARE applied but Content-Type is overwritten:
Affected Versions
Testing revealed:
Since PR #1736 introduced both the fetch handler pattern AND the
mapResponseBody()function, all versions with fetch handler support have this bug.No Workaround Available
Elide.httpwas removed in feat: new server engine #1736)Environment