Repository navigation
Conversation
The bundler gives each output its type. For an output that is in memory, set_blob_mime stored the type but did not mark it as set, so every reader that sends only a set type dropped it: a Response route, a fetch() upload, and the stream of the output. An output written with outdir is a file, and a file's type already counts as set.
|
Updated 9:02 AM PT - Oct 31st, 2026
❌ @robobun, your commit 79d3949 has 1 failures in
🧪 To try this PR locally: bunx bun-pr 47547That installs a local version of the PR into your bun-47547 --bun |
|
Caution Review failedAn error occurred during the review process. Please try again later. No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
MIME flag and propagation coverage src/runtime/api/output_file_jsc.rs, test/bundler/bun-build-api.test.ts |
set_blob_mime marks the content type as explicitly set. Tests check JavaScript and JSON content types and verify that an explicit text/plain request header takes precedence. |
Suggested reviewers: jarred-sumner, alii
Merge Risk: 
Minimal · up to 79d39
-
No actionable merge-blocking risk is identified in the MIME propagation change; merge after normal checks pass.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description explains the problem, fix, behavior changes, downsides, and verification results. It does not use the template headings exactly, but it provides the required information in equivalent sections.
-
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
There was a problem hiding this comment.
LGTM — a one-line flag set that brings in-memory build artifacts in line with file-backed ones and new Blob(bytes, { type }).
What was reviewed:
set_blob_mimenow mirrorsstandalone_graph_jsc.rs:52; the flag is consumed byhas_content_type_from_user(fetch uploads),Body.rs(.blob()fallback to text) andByteBlobLoader::setup(stream()), andBlob::slicepropagates it, so all nine assertions in the new test exercise the change (eight fail on base,uploadWithHeaderis the negative contract).- Checked the
file-loader / unknown-extension case:to_mime_typereturnsapplication/octet-stream, which now gets sent — same as theoutdirpath already does, so not a regression. - HTML-route caller (
HTMLBundle.rs:523) readscontent_type_or_mime_type(), which ignores the flag — unaffected.
Extended reasoning...
The diff adds blob.content_type_was_set.set(true) in the shared set_blob_mime helper in src/runtime/api/output_file_jsc.rs (used by both to_js and to_blob for the in-memory Buffer variant) and one hermetic test in test/bundler/bun-build-api.test.ts using port: 0 and await using. It touches no security-sensitive surface; it only affects which Content-Type header is emitted for in-memory Bun.build outputs on routes, streams and fetch uploads. Approve was decided by the change being a single line that copies an existing sibling pattern, the test covering every consumer of the flag plus the explicit-header precedence case, and no CODEOWNERS entry or outstanding reviewer objection on the changed files.
|
CI build 136099 is complete: 183 of 188 jobs passed. The 5 red jobs have one cause. |
Related to #3011
Problem
routes: { "/app.js": new Response(output) }sends noContent-Typefor an in-memoryBun.build()output (nooutdir).response.headersreports the type.set_blob_mime(src/runtime/api/output_file_jsc.rs:23) stores the type and does not setcontent_type_was_set. Readers that send only a set type drop it.Fix
set_blob_mimesetscontent_type_was_set, as embedded files do (standalone_graph_jsc.rs:52).new Blob(bytes, { type }). Of 22 readers compared on both builds, 6 change (Notes).test/bundler/bun-build-api.test.ts(the new test fails on main in 8 values). Also the route suites,blob,body,response.StaticRoute::from_js. The review asked for the producer and a declared upload change. Both are here.Background
BuildArtifactwraps aBlob: a file withoutdir, bytes without it.fetch()request andblob.stream()send only a set type.StaticRoute::from_js. It repairs one reader of ten, and http: consolidate the open fetch, Bun.serve, node:http, node:http2 and HTTP/3 pull requests #46528 rewrites that function.Downsides
fetch(url, { body: output })now sends theContent-Typeof the output, as anoutdiroutput does.output.stream()as a body sends it too. Both sent none. A caller that needs noContent-Typemust set its own.new Response(output.stream())sends that type, notapplication/octet-stream..text+256 bytes, same file size (GNUsize).Notes
What changes.
outputis the entry point of an in-memory build, a slice of it, or its source map. Debug builds of main 34cbc70 and of this branch, one script, 22 readers for each of 6 bodies. Every row that is not listed is the same on both builds.new Blob(bytes, { type })outdiroutputnew Response(output):Content-Typenew Response(output.stream()):Content-Typeapplication/octet-streamfetch(url, { body: output })sendsfetch(new Request(url, { body: output }))sendsfetch(url, { body: output.stream() })sends(await new Response(output.stream()).blob()).typetext/plain;charset=utf-8The same on both builds:
output.type,output.slice().type,new Response(output).headers, a handler'snew Response(output)for GET and HEAD,new Request(url, { body: output }).headers, a request with its ownContent-Type,(await new Response(output).blob()).type,Bun.readableStreamToBlob(output.stream()),new Blob([output]),new File([output], name),fetch(URL.createObjectURL(output)).Each kind of output. Release builds of main 34cbc70 and of this branch, one build with an entry point, a CSS asset, a source map, a
.pngasset and an asset whose extension has no known type (its type isapplication/octet-stream). On this branch a route, a handler and an upload send the same type for the in-memory output as for theoutdiroutput, for every kind. On main the route and the upload of the in-memory output send none.A deleted header. A route sends the type of an output also after
response.headers.delete("content-type"). That is main's rule for a set type: a route does so for a typed Blob on main, and afetchhandler does so for an output on main. AContent-Typethat the caller gives to theResponsereplaces the type, as before.The second caller.
set_blob_mimealso types the Blobs of HTML routes (OutputFile::to_blob,src/runtime/server/HTMLBundle.rs:519). Those routes write theirContent-Typefromcontent_type_or_mime_type(), which does not read the flag.bun-serve-html.test.ts,bun-serve-html-entry.test.tsandbun-serve-html-manifest.test.tspass.Other producers.
blob.slice(start, end, type), the body of adata:URL and a multipart part typed by its file name lose their type on a route in the same way (measured on 1.4.3). They are other producers, and this PR does not change them. #46516 and #47335 are open forslice().Overlap. #46114 removes the
store.mime_typewrite fromset_blob_mime, one line below this one. #46528 does not touch this file.The ETag of #3011 is not in this PR. It needs a maintainer decision. The issue has the details.
Suites on the debug ASAN build.
bun-build-api(92 pass, 1 skip, 1 todo),bun-serve-static,bun-serve-html,bun-serve-html-entry,bun-serve-html-manifest,bun-serve-html-405,bun-serve-routes,bun-serve-file,serve-if-none-match,blob,body,response,stream-fast-path,bun-cryptohasher, regression10004.Tools. The container has no
bloaty. The size is from GNUsize.