You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An explicitly empty If-Match: field arrives over the real HTTP socket, but the Worker sees it as absent: request.headers.get("If-Match") returns null instead of "". This occurs through the Miniflare frontend and through a direct workerd socket that bypasses that frontend.
The original application symptom was a conditional GET expecting 412 returning 200. The field is already missing before application handling, so this report is about transport preservation, not a request for an application workaround.
Observed environment
Linux x86_64; workerd npm package 1.20261021.1, executable reporting 2026-10-21.
Miniflare 5.20261019.1-beta from the existing Wrangler 4.151.3 installation; Node 26.12.0.
Worker compatibility date 2026-03-23.
The actual runtime binary matches the official npm binary for workerd source 1038810cb01af7860b0d576ee893ceb656bd5e98; its pinned KJ/Cap'n Proto dependency is a49c8fb48462987aafd612220de2d7a6c3f3d211.
These are observations of this local runtime, not a claim about deployed Cloudflare Workers, every platform/version, or HTTP/2 and HTTP/3.
Real-transport reproduction
Use the following receiver Worker and send GET /robots.txt over its actual HTTP socket, distinguishing an absent field, an empty field (If-Match: followed immediately by CRLF), and If-Match: "fixture-tag".
This is the tested receiver body with formatting expanded. In the executed matrix, every request came from the same native canonical HTTP API. A transparent TCP pass-through recorded and forwarded the original bytes without inserting/replacing headers. No in-memory Request, dispatchFetch(), substitute client, carrier header or application workaround was used.
Supplied field
Plain HTTP receiver
Miniflare frontend -> Worker
Direct workerd socket -> Worker
Absent
null
null
null
Empty
""
null
null
"fixture-tag"
exact value
exact value
exact value
The empty field is present in the TCP observation for both affected routes. The nine-case native transport matrix executed 7 passes / 2 failures; only those two empty Worker cases failed. The diagnostic receiver intentionally returns JSON/200 for all variants: its oracle is the exact field value, not the original application's separate 412 assertion. Ordinary unconditional GET behavior was also checked separately.
Identified upstream cause
The factory shares the header-table builder with HttpOverCapnpFactory, whose common-name table includes If-Match.
The Hyper ingress HeaderBlock copies the zero-length value and its length. headers_from_block in src/rust/cxx/kj-hyper/kj-hyper.c++ calls HttpHeaders::addPtrPtr with it.
KJ stores indexed values as StringPtr, using == nullptr as the absent test. KJ's empty StringPtr also compares equal to nullptr, so insertion loses distinguishable presence; lookup/iteration/clone/serialization then omit the field.
The Worker Headers constructor copies via KJ iteration. Unindexed empty fields do not have the same representation problem.
The proposed upstream correction is capnproto/capnproto#2878 (draft). It stores indexed presence independently using Maybe<StringPtr>, without changing global StringPtr semantics, the client or application policy. Four native KJ regressions fail on the original source and pass with the patch; the complete native HTTP test executable passed 153/153 cases on the pinned source plus the fix. Those counts include the four new cases, and are not a patched workerd result.
The KJ PR targets the newer v2 base 4903846ea6a0f32b2be3deaf8009795829c3f70c, with the exact same three HTTP file changes. Its current-base rerun is pending CI because fresh local capacity planning did not permit another build. No rebuilt-workerd or post-fix application 412 result is claimed.
Requested resolution
Once the KJ fix is accepted, update workerd's selected dependency and add a real HTTP-ingress regression that preserves absent/empty/nonempty header distinctions. We will follow with that dependency/regression PR after acceptance. The original 412 assertion, unconditional GET behavior and deadlines should remain unchanged.
Reference: RFC 9110 If-Match. This report does not assert a security severity, CVE, authentication bypass or production-platform exploit.
Activity