Skip to content

SINGLE_FILE_BINARY_ENCODE: report a non-UTF-8 read clearly instead of a wasm CompileError #28048

Open

Description

@piandtheradians-glitch

I was integrating a tool depending on this one and traced my issue to your report. My agent has a proposed fix I am happy to deliver for your review.

(The tool is Verovio, the music engraver, in a piano app. The report is #27156, where the same kind of error came up and the question below was asked.)


With -sSINGLE_FILE and the default SINGLE_FILE_BINARY_ENCODE=1, a .js that the browser reads as anything other than UTF-8 fails with an error that points at the wasm, not at the encoding:

failed to asynchronously prepare wasm: CompileError: WebAssembly.instantiate(): unknown type form: 85 @+12

The UTF-8 requirement is documented in settings.js, but nothing at run time says that this is what went wrong, so it is easy to spend a while suspecting the build, the browser or wasm feature support. In #27156, @sbc100 asked: "I wonder if we can do better at detecting and reporting this kind of problem?" This issue is a proposal for that.

How I ran into it

The npm package verovio@6.3.0 (dist/verovio-toolkit-wasm.js, built with SINGLE_FILE and binary encoding) loaded from a hand-written test page with no <meta charset>, served from file://, in Chromium 156. The page is read as Windows-1252, the embedded string is mis-decoded, and the error above follows. Adding <meta charset="utf-8"> fixes it; so does setting script.charset = "utf-8" on a dynamically added <script>. (Verovio 6.2.0 behaves the same; 5.7.0, which predates binary encoding, does not.)

Minimal page:

<html><body>
<script src="node_modules/verovio/dist/verovio-toolkit-wasm.js"></script>
<script>verovio.module.onRuntimeInitialized = () => console.log(new verovio.toolkit().getVersion());</script>
</body></html>

Why it is cheap to detect

Read correctly, every byte of the wasm becomes exactly one character of the string (the escapes \\, \r, \n and the quote all decode to one character), so bin.length equals the wasm's size, which binary_encode() in tools/link.py already knows. Read as Windows-1252, every byte ≥ 0x80 (two bytes of UTF-8) becomes two characters, so the length is off. On Verovio 6.3.0's embedded module: 6,873,529 characters as UTF-8 vs 7,226,048 as Windows-1252, and 168,000 characters above U+00FF in the wrong reading (none in the right one), the first at index 10.

Proposal

Emit the expected length with the data, e.g. binaryDecode("…", 6873529), and in binaryDecode() compare it with bin.length once before decoding. On a mismatch, abort with something like:

The embedded wasm was not read as UTF-8 (SINGLE_FILE_BINARY_ENCODE). Serve the file with charset=utf-8, add <meta charset="utf-8"> to the page, or build with -sSINGLE_FILE_BINARY_ENCODE=0.

That is one integer in the output and one comparison at start-up, nothing per byte, so it can stay on in release builds (where most people would hit it) rather than only under ASSERTIONS. If the message itself is too much for -Oz, it could be a short message in release and the full one under ASSERTIONS.

If the approach sounds right, I'll send it as a PR with a browser test that loads a SINGLE_FILE build from a non-UTF-8 page.

Disclosure: researched and drafted by Claude (Claude Code) at my direction. The error and the <meta charset> fix are from real runs against verovio 6.2.0 and 6.3.0 in Chromium 156, the script.charset fix and the character counts from 6.3.0; the encoder behaviour was checked against tools/link.py and src/binaryDecode.js on main.

Activity

  1. sbc100 commented on Oct 22, 2026

    @sbc100
    Collaborator

    Sounds good to me! Please sense PR for that. ASSERTIONS only seems fine to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions