Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallYou can render share-card PNGs inside a Cloudflare Worker with Satori and resvg-wasm, but the working route is narrower than the libraries’ general documentation suggests. Satori turns a layout tree into SVG, @resvg/resvg-wasm turns that SVG into PNG, and the chain only runs reliably in the Workers runtime once the WebAssembly is bundled and loaded the way workerd expects. The most detailed production account available is Robert Gordon’s write-up of Commit Archive, a single Cloudflare Worker that generates Open Graph images on demand. This guide sets out his implementation path, the four failures he reported, what is general platform behaviour and what is specific to his application, and a checklist for testing the same setup in your own deployment.
What Gordon built and what it proves
Commit Archive generates a 1200×630 Open Graph image for each archived project and a 1080×1350 contributor card, both on demand. Gordon’s application runs as one Cloudflare Worker using Next.js through OpenNext, with D1, Queues and R2. Rendered cards are cached in R2. Live cards are served with short cache headers, and cards become immutable once their edition is sealed.
Those dimensions and cache rules are his application’s choices, not requirements from Cloudflare or Satori. The write-up is dated 16 September, and the page does not show a year, so treat the details as a snapshot of that codebase rather than a dated platform specification.
The rendering pipeline
- Build the card as a plain
{ type, props }object tree. Gordon does this so the same renderer can be called from an API route and from a queue consumer without React in the job path. - Pass the tree to Satori, which converts it to an SVG string. Text is embedded as glyph outlines (SVG path data) by default, so the output does not depend on fonts being installed on the client.
- Pass the SVG to
@resvg/resvg-wasm, which renders it to PNG at the card’s pixel size. - Return the PNG directly for live requests, or write it to R2 for cached and sealed cards.
What Satori does and does not do
Satori accepts JSX or React-element-like objects, but it implements a subset of HTML and CSS rather than a full browser. Its README says it cannot guarantee that output matches browser-rendered HTML exactly, so design cards against the subset it documents and check the result visually.
#1 Best Overall
Satori accepts TTF, OTF and WOFF font files. It does not support WOFF2, so a font that works in a website’s CSS may still fail in the renderer. Text rendering needs explicit font data: an ArrayBuffer in the web build or a Buffer in Node.js.
Font delivery in Gordon’s setup
Gordon vendors TTF files into the repository and shares the same font files with the website. This keeps the card typography reproducible across builds, and it avoids a runtime font request inside the Worker. The trade-off is that font files become part of the bundle, so their size counts toward the WebAssembly and deployment footprint you are already managing.
Build and runtime setup that runs under workerd
Gordon’s working configuration differs from the simplest Satori example in three ways:
- Satori is pinned to the 0.15.x line. He imports the
satori/wasmentry and pairs it withyoga-wasm-web. - Yoga and resvg are imported as compiled modules. A
CompiledWasmrule inwrangler.jsoncmakes the.wasmfiles importable as precompiled modules:
{
"rules": [
{ "type": "CompiledWasm", "globs": ["**/*.wasm"] }
]
}
- resvg is initialised once per isolate with the compiled module before the first render. Gordon measured this initialisation at about 93 ms per isolate.
Cloudflare’s WebAssembly documentation, last updated 23 April 2026, confirms that Workers can instantiate precompiled modules through WebAssembly.instantiate(). It also notes that each Worker runs in a single thread, that threads and the Web Worker API are not supported, and that WASM dependencies usually increase Worker size and can increase startup time. It recommends wasm-opt for reducing binary size.
A community project, the Cloudflare WASM Modules repository, lists @cf-wasm/og as a dynamic Open Graph renderer built on Satori and resvg, with separate Satori and resvg packages listed as compatible with Workers. It is a third-party option, not an official Cloudflare endorsement, and Gordon’s write-up does not use it.
The four failures
1. “Wasm code generation disallowed by embedder”
Symptom. The renderer worked under Node but failed on workerd with the error Wasm code generation disallowed by embedder.
Rank #2
Cause, as Gordon diagnosed it. Newer Satori versions, in his testing, used harfbuzzjs, which tried to locate its WASM file through location.href at import time. That lookup failed inside this Worker setup.
Mitigation he used. Pin Satori to 0.15.x, import through satori/wasm with yoga-wasm-web, and import the Yoga and resvg modules through the CompiledWasm rule shown above.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
What to verify. This is version- and build-specific. Check the Satori package documentation for the version you install, and do not assume a newer release behaves the same way. The general lesson from his report is that a Node success does not prove workerd compatibility. Gordon’s own conclusion was: “Lesson: test the renderer under wrangler dev, not only in Node.”
2. “TypeError: Illegal invocation”, only in the queue consumer
Symptom. Card generation succeeded through the Next request handler but threw TypeError: Illegal invocation when run from the queue consumer.
Cause, as Gordon diagnosed it. A GitHub client stored fetch as a method and later called it as this.fetchImpl(url). Gordon reports that Next’s request path patches globalThis.fetch, which masked the receiver problem. The raw Worker queue entry exposed it.
Mitigation. Wrap the call as a free function so the receiver is not bound to the client object:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #3
((input, init) => fetch(input, init))
What to verify. This is an author-reported diagnosis. Exercise each entry path separately, including the queue consumer, and confirm the failing call in your own runtime before applying the wrapper.
3. GitHub contributor statistics return HTTP 202
Symptom. GET /repos/{owner}/{repo}/stats/contributors returned 202 Accepted with no body while GitHub computed the statistics.
Observed behaviour. For one test repository, the statistics took about 15 minutes to appear, and the initial job exhausted five retries. This is Gordon’s single reported example, not a guaranteed processing time.
Mitigation. From the first retry onward, the application published the contributor card without line counts. A later scheduled refresh filled in the counts once GitHub had them. Gordon changed the product flow rather than treating the pending response as a fatal job error.
What to verify. Decide what the card shows while statistics are pending, and make the refresh path idempotent so a later run can complete the card.
4. Error 1027 from a different Worker
Symptom. Requests failed with Cloudflare error 1027, which Gordon quotes as “temporarily rate limited.” The failures appeared across environments at about the same time, which made the rendering code look responsible.
Rank #4
Cause, as Gordon diagnosed it. Another Worker on the same account was generating a few hundred thousand requests per day. Gordon reports that the Free plan’s 100,000 daily requests were shared across the account at the time.
Mitigation. He moved the other Worker off its public route. He later moved the account to Workers Paid, which also raised the CPU limit that matters for large ingestion jobs.
Free tools Windows power users keep installed
One-click scans. No signup required.
What to verify. The Cloudflare WebAssembly page does not confirm these quota figures, and plan limits change. Check the current plan documentation in your dashboard before treating either number as today’s limit.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Performance figures from one workload
Gordon measured the following on warm isolates in his own application. These are not comparative benchmarks and do not describe cold starts or other workloads.
| Card | Pixel size | Average render time | Average PNG size |
|---|---|---|---|
| Project Open Graph card | 1200×630 | About 56 ms | About 38 KB |
| Contributor portrait card | 1080×1350 | About 82 ms | About 42 KB |
Caching pattern
Gordon’s application caches rendered PNGs in R2. Live cards carry short cache headers because their data can change, and cards are marked immutable after the edition is sealed. He does not compare this with other caching strategies, so the pattern is a reasonable starting point rather than a tested optimum.
Verification checklist for your own deployment
- Run every card type under
wrangler devand compare the output against a visual reference. Use Node only as a secondary check. - Exercise the API route and the queue consumer as separate entry points, and confirm each makes its outbound
fetchcalls without errors. - Inspect the built bundle to confirm the
.wasmfiles are imported as compiled modules, and confirm the Satori and Yoga versions match the ones you tested. - Confirm every font file is TTF, OTF or WOFF, not WOFF2.
- Handle GitHub’s 202 response as a pending state, with a scheduled retry that completes the data later.
- Check the account for other Workers that might be consuming shared daily requests, and confirm current plan limits in the Cloudflare dashboard.
- Record cold-start and warm render timings for your own card sizes and data volume. Run
wasm-opton the WebAssembly to reduce size.
Before copying the setup, decide the choices that matter for your project: whether to write templates as JSX or plain object trees, whether you need SVG or PNG output for the platforms you target, how long cards should stay cached, and whether to vendor fonts or load them another way.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

