Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk7 min

Rendering Share Cards on Cloudflare Workers with Satori and resvg-wasm: Four Failures and Their Fixes

Satori turns a layout tree into SVG and resvg-wasm turns it into PNG. Robert Gordon's Commit Archive account of running that chain on Cloudflare Workers covers four failures, their fixes, and what to verify in your own deployment.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

You can render share cards inside a Cloudflare Worker with Satori and resvg-wasm, but the working setup depends on how the WebAssembly is bundled and loaded, not only on which libraries you choose. Satori turns a layout tree into SVG, and resvg converts that SVG into PNG. The hard part is the Worker runtime. Robert Gordon’s write-up of building the card generator for Commit Archive reports four separate failures: a WebAssembly loading error, a fetch receiver bug that appeared only in a queue consumer, an asynchronous GitHub API response, and an account-level request limit that broke several Workers at once.

Everything below comes from that one production account. Commit Archive is a single Worker application that uses Next.js through OpenNext, D1, Queues and R2. Where a number or behavior is specific to that app, this guide says so. Where it reflects documented Cloudflare or Satori behavior, it is labeled that way.

As an Amazon Associate I earn from qualifying purchases.

How the rendering chain works

Gordon’s templates are plain { type, props } object trees rather than React components. That lets the same renderer run from an API route and from a queue consumer without React in the job path. The chain has two stages:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Satori converts the element tree into an SVG string.
  • @resvg/resvg-wasm converts that SVG into a PNG.

Satori converts text into SVG path data by default, so glyph outlines are embedded in the SVG itself. Text rendering also needs explicit font data: an ArrayBuffer in web builds, or a Buffer in Node.js. Satori implements a subset of browser layout and CSS rather than a full browser, and it does not guarantee that its output matches browser-rendered HTML. Design cards against what Satori supports, and check them visually.

Card sizes and reported performance

Commit Archive uses two card formats. Neither size is imposed by Cloudflare or Satori; they are the sizes this application chose.

Card Dimensions Reported average render time Reported PNG size
Project Open Graph card (one per archived project) 1200×630 px About 56 ms, warm isolate About 38 KB
Contributor card (portrait) 1080×1350 px About 82 ms, warm isolate About 42 KB

Gordon also reports about 93 ms of WebAssembly initialization, paid once per isolate. These are measurements from his application, and the write-up does not state the test hardware or sample size. Treat them as an order-of-magnitude reference, not a benchmark. The write-up is dated September 16, but the year does not appear on the page.

Platform facts and one team’s observations

Before setting anything up, separate what the platform and libraries document from what Gordon observed in his own deployment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Point Source Scope
Workers can run WebAssembly through WebAssembly.instantiate() with precompiled modules Cloudflare Workers WebAssembly documentation, updated April 23, 2026 Platform
Each Worker runs in a single thread; threading and the Web Worker API are not supported Cloudflare Workers WebAssembly documentation Platform
WASM dependencies typically increase Worker size and may increase startup time; wasm-opt is recommended for binary size Cloudflare Workers WebAssembly documentation Platform
TTF, OTF and WOFF are supported; WOFF2 is not Satori README Library
Standalone Satori builds leave out Yoga’s WASM binary, which you supply and initialize with init before rendering Satori README Library, general standalone guidance
Pinning Satori to 0.15.x, using the satori/wasm entry with yoga-wasm-web, and importing WASM through a CompiledWasm rule Gordon’s Commit Archive setup One application, one version
Newer Satori versions failing on import in that setup Gordon’s Commit Archive setup Version and build specific
Community packages such as @cf-wasm/og wrapping Satori and resvg for Workers Cloudflare WASM Modules repository (community project, not an official Cloudflare endorsement) Third-party option

Setup: bundling WASM and loading fonts

The platform allows precompiled WebAssembly modules, but the Satori standalone path assumes you can fetch and initialize Yoga at runtime. Gordon’s arrangement compiles the modules at build time instead. In outline:

  1. Pin Satori to the 0.15.x line in your project. Gordon’s report ties this pin to the failure described below, so confirm the version you install.
  2. Import the satori/wasm entry and provide Yoga through yoga-wasm-web.
  3. Import the Yoga and resvg WebAssembly modules through a CompiledWasm rule in wrangler.jsonc, so they are compiled as part of the build.
  4. Vendor the font files you need as TTF, since WOFF2 is not supported. Gordon shares the same font files with his website, so a single source of truth covers both.
  5. Run the Worker with wrangler dev and render a card before deploying anything.

Keep the font step deliberate. A font that works in a browser may be WOFF2 by default, and Satori will not read it. Converting or sourcing TTF files early avoids a late surprise.

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.

Cause, as Gordon diagnosed it. The newer Satori release he tried used harfbuzzjs. That library tried to locate its WebAssembly through location.href at import time, which failed in his Worker setup. The fix he describes was the pinned 0.15.x line, the satori/wasm entry, and compiled imports for Yoga and resvg.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What to verify. Check which Satori version resolves in your lockfile, and do not assume a newer release behaves the same. Run the card route under wrangler dev. A successful run in Node proves only that the code is correct in Node.

2. TypeError: Illegal invocation, only in the queue consumer

Symptom. Card generation succeeded through the Next.js request path but threw Illegal invocation inside the queue consumer.

Cause, as Gordon diagnosed it. His GitHub client stored fetch as a method and later called it as this.fetchImpl(url). The Next.js request path patched globalThis.fetch, which masked the receiver problem. The raw Worker queue entry did not have that patch, so the bug surfaced there.

Fix. Wrap the call in a free function so the native function is not invoked with the wrong receiver: ((input, init) => fetch(input, init)).

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What to verify. Exercise every entry point that calls outbound fetch, not only the request handler. Gordon’s report is a single diagnosis, so confirm the call path in your own code.

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 timing. For one test repository, the statistics took about 15 minutes to appear, and Gordon’s initial job exhausted its five retries. This was one observed case, not a guaranteed processing time, and other repositories may resolve faster or slower.

Change in product behavior. From the first retry onward, the job published the project without line counts. A later scheduled refresh filled in the counts once GitHub had computed them. Gordon treats the 202 as a pending state to handle, not as a failure that stops the job.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What to verify. Design the publish step so it can complete without this data, and make sure the refresh path can update it later. Test with a repository whose statistics have not been requested recently.

4. Cloudflare error 1027, “temporarily rate limited”

Symptom. Requests failed with Cloudflare error 1027 across environments at about the same time, which made the problem look like a bug in Commit Archive.

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 whole account at that time.

Mitigation. He moved the other Worker off its public route, then moved the account to Workers Paid. The upgrade also raised the CPU limit, which matters for large ingestion jobs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What to verify. Check the account’s Workers analytics for a neighboring Worker before debugging your own code when several Workers fail together. Plan quotas and prices change, and the Cloudflare WebAssembly documentation does not confirm the 100,000-request figure. Read the current plan documentation before relying on any quota.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Caching and edition state

Gordon’s app stores rendered cards in R2. Live cards use short cache headers because their content can still change. Once an edition is sealed, its cards become immutable and can be cached for longer. He does not benchmark this against other strategies, so treat it as a pattern to adapt, not a tested optimum.

Verification checklist

Gordon’s practical lesson is worth quoting in full: “Lesson: test the renderer under wrangler dev, not only in Node.” Before you ship a share-card renderer on Workers, check each item:

  • Render at least one card of each size under wrangler dev and compare the PNG output with what you expect.
  • Confirm the resolved Satori version and whether it matches the bundling setup you tested.
  • Confirm that Yoga and resvg are imported as compiled modules, and that the build produces them without runtime fetches.
  • Confirm every font file is TTF or OTF (or WOFF, if you use that format), not WOFF2.
  • Exercise the request route, the queue consumer and any scheduled job, since each can expose a different fetch or runtime behavior.
  • Handle a GitHub 202 response as pending. Make sure publish can complete without the data and that a later job fills it in.
  • Record cold and warm render times, PNG sizes and WASM initialization time for your own cards, not the figures quoted here.
  • Check account-level request and CPU limits against the current plan documentation, and look for other Workers on the same account.

The sequence matters. Gordon’s failures came from runtime differences that a Node test would never reveal, so the Worker runtime should be the environment that signs off on the renderer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.