Skip to content

Follow the Fetch spec for statusText - #7839

Open
npaun wants to merge 1 commit into
mainfrom
npaun/pedantic-wpt-status-text
Open

npaun wants to merge 1 commit into
mainfrom
npaun/pedantic-wpt-status-text

Conversation

@npaun

@npaun npaun commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

The Fetch spec gives a response an empty status message unless something sets it. ResponseInit.statusText defaults to "", and only the scheme fetch steps set a value: OK for data:/about:blank, and OK/Partial Content for blob:. workerd instead derived the reason phrase from the status code, so new Response(null, { status: 404 }).statusText was "Not Found", and the same went for Response.json() and Response.redirect().

Now:

  • An unset statusText is "".
  • A Response initialized from another Response (constructor or Response.json()) copies its status message exactly.
  • fetch() responses keep the reason phrase the server sent, even when it matches the default.

data: URL fetches now set "OK" explicitly, which is the value they already reported. workerd doesn't fetch blob: or about: URLs.

The HTTP reason phrase on the wire is unchanged. An unset status message still sends the conventional phrase (new getReasonPhrase()), so HTTP clients see no difference. Error messages that include the status, such as Fetcher's put()/get() helpers, use the same phrase.

Fixes #4973

Compatibility

This changes behaviour for all Workers, on every compatibility date, with no compatibility flag. For example, new Response(null, { status: 404 }).statusText becomes "" where it was "Not Found", and Response.json() / Response.redirect() results report "" where they reported "OK" / "Found". This follows James Snell's review, which questioned gating the change behind pedantic_wpt.

The statusText expected failures in response-init-001, response-static-redirect, response-static-json and response-clone are removed from both fetch WPT configs. The js-rpc-test and Python SDK test expectations that relied on the derived phrase are updated.

🤖 Generated with Claude Code

@npaun
npaun force-pushed the npaun/pedantic-wpt-status-text branch 2 times, most recently from c10c3c3 to c2e7db2 Compare October 22, 2026 21:20

@jasnell jasnell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not entirely convinced this needs to be gated but don't feel strongly about it.

@npaun
npaun force-pushed the npaun/pedantic-wpt-status-text branch from c2e7db2 to 56aa00f Compare October 28, 2026 22:38
@npaun npaun changed the title Follow the Fetch spec for statusText under pedantic_wpt Follow the Fetch spec for statusText Oct 28, 2026
@npaun

npaun commented Oct 28, 2026

Copy link
Copy Markdown
Member Author

Dropped the gate. Could you please take a quick look again before I merge?

@npaun
npaun marked this pull request as ready for review October 28, 2026 22:40
@npaun
npaun requested review from a team as code owners October 28, 2026 22:40
@npaun
npaun requested a review from jasnell October 28, 2026 22:40
The Fetch spec gives a response an empty status message unless
something sets it: ResponseInit.statusText defaults to "", and
"initialize a response" copies it as-is. Only the scheme fetch
steps set one, to `OK` for data: and about:blank URLs and to `OK`
or `Partial Content` for blob: URLs. workerd instead derived the
RFC 9110 reason phrase from the status code, so
`new Response(null, { status: 404 }).statusText` was "Not Found"
rather than "", and likewise for Response.json() and
Response.redirect().

An unset statusText is now "". A Response initialized from another
Response, through the constructor or Response.json(), copies its
status message exactly. Responses returned by fetch() keep the
reason phrase the server sent, even when it matches the status
code's default. data: URL fetches now set "OK" explicitly, which
is the value they already reported. workerd does not fetch blob:
or about: URLs.

The HTTP reason phrase sent for a Response returned to a client is
unchanged: an unset status message still sends the status code's
conventional phrase, so HTTP clients see no difference even though
the JS-visible statusText is empty. Error messages that include a
response's status, such as those thrown by Fetcher's put() and
get() helpers, use the same conventional phrase.

Compatibility: this changes behaviour for all Workers, on every
compatibility date, with no compatibility flag. For example,
`new Response(null, { status: 404 }).statusText` becomes "" where
it was "Not Found", and Response.json() and Response.redirect()
results report "" where they reported "OK" or "Found". This
follows James Snell's review, which questioned gating the change.

The statusText expected failures in response-init-001,
response-static-redirect, response-static-json and response-clone
("Check Response's clone with default values, without body") are
removed from both fetch WPT configs. The js-rpc-test and Python
SDK test expectations that relied on the derived phrase are
updated.

Fixes #4973

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@npaun
npaun force-pushed the npaun/pedantic-wpt-status-text branch from 56aa00f to 5176a4e Compare October 28, 2026 22:41
@clanky-the-clanker

Copy link
Copy Markdown

💬 Approved with comments — The statusText change is correct and the reason phrase sent on the wire is unchanged. Two notes: the ungated behaviour change, whose risk the commit message records as accepted, and a stale test comment.

Findings: 1 info · 1 suggestion

The decision is advisory: this comment never approves, blocks or requests changes on the pull request.


📋 Code Quality: 💬 1 info · 1 suggestion

The logic is correct and no call site was missed. Two notes: the ungated behaviour change and a stale test comment.

Recommendation: 💬 Optional Nits

  • [INFO] The statusText change has no compatibility flag, so every Worker sees it on every compatibility date. The commit message records that the risk is accepted, and @​jasnell, who approved the pull request, saw no need for a flag. Noted for awareness. (src/workerd/api/http.c++:1357)
  • [SUGGESTION] The comment still says "These Workers run without pedantic_wpt", which is left over from the gated version. The behaviour is now unconditional, and the @​all-compat-flags variant may enable the flag. Remove the sentence. (src/workerd/api/tests/response-status-text-test.js:7)
View full review

Ungated behaviour change (src/workerd/api/http.c++:1357, :1081, :1210)

Every Worker, on every compatibility date, now sees a different statusText:

  • new Response(null, {status: 404}).statusText returns "" instead of "Not Found".
  • Response.json() and Response.redirect() return "" instead of "OK" and "Found".

A Worker that logs statusText, branches on it, or copies it into its own response bodies will behave differently. The repository's rule is to put the change behind a compatibility flag or to record in the commit message that the risk is accepted. The commit message does the second, and @​jasnell, who approved the pull request, was not convinced a flag is needed. Noted for awareness only.

Code paths checked

  • The status line sent on the wire and the error messages from Fetcher's get()/put() use getReasonPhrase() (http.c++:1342, :1349, :2683, :2739). HTTP clients see no change.
  • Clone, RPC serialization, the cache path and HTMLRewriter's re-wrapping all match the new semantics.

Stale test comment (src/workerd/api/tests/response-status-text-test.js:7)

The comment says "These Workers run without pedantic_wpt, which WPT always enables." That wording comes from the version gated on pedantic_wpt. The behaviour no longer depends on the flag, and the @all-compat-flags variant may enable it anyway. Drop the sentence.


✅ All other checks passed

🔒 Security: ✅ LGTM

No security concerns. The reason phrase sent on the wire is unchanged. statusText validation is unchanged.


📖 AGENTS.md: ✅ LGTM

No AGENTS.md updates needed.


⚡ Performance: ✅ LGTM

No hot-path cost: one small string clone or allocation per response.


📝 Documentation: ✅ LGTM

No documentation issues.


Reviewed commit: 5176a4e5

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.

If pedantic_wpt is set, make sure statusText is only set when the fetch spec says so

2 participants