Build1 distinct publisher2 min readPublished
Safari's "accessed before initialization" errors came from host hooks specified in a proposal last touched in 2016, before async/await existed in the language. WebKit rebuilt the loader rather than patch it again.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Follow any of these and your For You feed starts watching them — no settings page required.
build
canvas.toBlob hands you a PNG and calls it WebP: check blob.type, not the user agent1 distinct publisher
build
pnpm 12's 90% install figure comes off a 1.5-second baseline1 distinct publisher
build
A receipt intent written before dispatch turns an SMS timeout into a poll instead of a resend1 distinct publisher
build
A key in the app binary is a bucket handover; presigned uploads also drop the proxy data bill1 distinct publisher
WebKit's own example is the receipt. test-module.js awaits a 10ms setTimeout promise at the top level, then declares `someFunction` and `someArray` below it [14]. main.js dynamically imports that module three times and prints the keys of each namespace, and the expected order is 1, 2, 3 [13]. Under the old loader the log reads Importing 1, Importing 2, Importing 3, then Imported 2 followed by "Accessing 2 failed: Cannot access 'someArray' before initialization", then Imported 3 with the same message [15]. Two of the three imports report that failure, and the published excerpt contains no "Imported 1" line at all [16]. The error text names the mechanism: the importer received a module namespace whose `const` binding, declared after the await, had not been initialized yet [17].
That is the failure mode you get when a loader learns which parts of the job are its own from a document that predates the feature. The ECMAScript modules section deliberately leaves the fetching mechanism to the host, over the network in a browser or off the filesystem in runtimes like Node.js and Bun [5]. Safari's loader took its host-defined behaviour from the WHATWG Loader proposal, whose last update was January 2016 [6], and that held up while module evaluation was purely synchronous [7]. Top-level await arrived in ECMAScript 2022 [8], six years after that proposal stopped being edited [21], and by then the standard's own module section had superseded it [9]. Safari kept implementing the feature in terms of the abandoned hooks instead of the standard's algorithms for asynchronous module execution [10], and the place it showed was the order in which modules were loaded and evaluated [12].
The engine fix reaches only what the engine controls; your bundler is a separate layer. If your build emits an output format that cannot express a top-level await, the construct is gone before Safari ever parses it, and the compliance work is invisible to your users. The thing worth checking is what your bundler produces for the entry module that would host the await, not only which browsers you target.
Rewriting a loader is expensive, and in this case necessary: host hooks designed for a synchronous execution model cannot be patched into agreement with an asynchronous spec, which is roughly what WebKit reports after years of attempts [11]. Note also the register of the pitch: if top-level await was not part of your toolkit, give it another look [22]. That is honest about where the remaining risk sits, which is in your build, not in the engine.
Ranked by verification strength, evidence, and original report placement.
Run under the old loader, the example printed Importing 1, Importing 2, Importing 3, then Imported 2, "Accessing 2 failed: Cannot access 'someArray' before initialization", then Imported 3 and the same access failure for 3.
WebKit for Safari 27 adds full spec compliance for top-level await.
WebKit says it fixed top-level await at the root by rewriting Safari's module loader from the ground up.
Before this change, developers may have run into unexpected "accessed before initialization" errors in Safari.
For ES modules, when a module encounters a top-level await, any module that imports it is also suspended until the await resolves; sibling modules in the dependency graph that do not depend on the awaiting module can still execute concurrently.
The ECMAScript specification's modules section leaves some parts up to the host, including the mechanism of fetching modules, done over the network by web browsers or from the local filesystem by runtimes like Node.js and Bun.
Distinct publishers with included, body-backed reporting in this cluster.
1 article · September 2, 2026
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Vendor-only, but runnable
One document from the team that wrote the bug is thin sourcing by any normal standard — and yet WebKit hands over the means to check it: a short main.js, a test-module.js that awaits a 10ms timeout before its exports, the exact failing transcript, and the exact fixed transcript. Claims of that shape either reproduce or they don't. What we cannot see is the implementation half; the discussion of self-hosted JavaScript builtins versus native C++ cuts off mid-word in our copy, so the how of the rewrite is asserted rather than shown.
Preview and beta only
The new loader exists today in exactly two places a normal user never runs: Safari Technology Preview 251 and the Safari 27 beta. Production use is explicitly deferred to a Safari 27 release that carries no date in this reporting, and nobody outside WebKit has yet reported trying the repro, shipping code that depends on it, or retiring a workaround because of it.
Narrow fix, broad promise
Two different claims are stacked here and only one is demonstrated. That the ordering bug is fixed in this example, in this build: shown, convincingly. That ES modules as a whole are now something to build on in Safari "without a second thought": a beta, one test case, and a vendor's assurance, with no inventory of remaining loader bugs to back it. The gap is modest because the technical writing is disciplined; it is real because the marketing sentence claims territory the demo never enters.
Self-report on a self-inflicted bug
WebKit is both the party that shipped a loader built on a 2016 proposal and the party telling us the rebuild was the right call. "We fixed it at the root" is the most flattering available description of a defect the same post admits went unresolved for years across multiple attempts — and the admission itself buys credibility for the invitation that follows it. The disclosure is more candid than the incentive would predict, which is why this sits below the top of the range rather than at it; nothing in it, though, has been checked by anyone with a reason to find fault.
Checkable, unchecked
We hold this at moderate for a specific reason: the load of the story rests on statements that are cheap to verify and expensive to fake, yet verification has not happened in public. The dates, the failure messages, and the download instruction are all precise; the rewrite's internals, the ship date, and any residual bugs are not in evidence at all. First independent reproduction on the beta would move this sharply either way.