Skip to content

Troubleshooting

Find your symptom, then check the cause and the fix. Errors carry a code (GPU_INIT_FAILED, INVALID_INPUT, …): the browser engine and the native host share the engine’s codes, and the host protocol lists the rest. Validation and errors explains how to handle them in code.

The canvas stays blank, or the engine fails with GPU_INIT_FAILED

Section titled “The canvas stays blank, or the engine fails with GPU_INIT_FAILED”

Cause. The engine could not create a GPU device. In a browser that means no WebGPU and no WebGL2 (hardware acceleration is off, the GPU is blocklisted, or the page runs in a VM), or only a software adapter when software adapters are refused. On a server it means no GPU driver the host can use.

Fix.

  • In the browser, let the engine fall back to the CPU renderer: createRenderer(binding, canvas, "auto") from alpha2/renderer-choice, or the worker host’s renderer: "auto", draws on the CPU when the GPU fails, and says which it made in rendererChoice. WebEffectRegistry.createCpu(canvas) makes the CPU renderer directly. It draws the same pixels, more slowly.
  • { softwareAdapter: "refuse" } on createForHtmlCanvas rejects SwiftShader, llvmpipe, WARP and WebGPU fallback adapters with GPU_INIT_FAILED. Drop it, or fall back to the CPU renderer, which is faster than a software adapter.
  • Natively, alpha2-host exits with status 70 on GPU_INIT_FAILED. Use --renderer auto (the default) or --renderer cpu on a machine without a GPU: --renderer gpu fails when there is no adapter.
  • Check what the browser offers on Platform support.

Cause. The engine has no frame for the sources the time shows. The application decodes media and uploads it; the engine draws only what it was given.

Fix. Read what renderAt(ticks) returns: missingSources and missingFrames name what it lacked. frameNeeds(ticks) lists the frames a time needs with their exact source times. Upload them (uploadVideoFrame, uploadRgbaFrame, uploadRgbaImage) and render again, or let FrameSupply from alpha2/frame-supply do it.

The export fails with GPU_DEVICE_HUNG or GPU_DEVICE_LOST

Section titled “The export fails with GPU_DEVICE_HUNG or GPU_DEVICE_LOST”

Cause. GPU_DEVICE_LOST: the device was lost (a driver reset, another program, a sleep). GPU_DEVICE_HUNG: the export’s own work kept the GPU busy for at least half the operating system’s GPU watchdog (2000 ms by default), so the OS reset it. Running the same work on that GPU again hangs it again.

Fix. Retry a lost device in a new process or on a new device: the native host exits after answering, and the browser player’s GpuRecoveryLadder does this for you. For a hung device, render on the CPU (--renderer cpu) or lighten the heavy frames. failure.diagnostics.gpuSubmission names the longest submission, its frame and its effects. decideRetry in alpha2/export-retry chooses between these.

Cause. The project uses a runtime WGSL effect. The CPU renderer draws every built-in effect and transition, but WGSL needs a GPU.

Fix. Render that project with --renderer gpu (or renderer: "gpu"), on a machine with a GPU.

Cause. Audio preview moves the mixed audio to the audio thread through shared memory, which needs a cross-origin isolated page. Video preview, editing and export work without it.

Fix. Serve the page with both headers:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

canShareAudioMemory() from alpha2/audio-timeline says whether the page is isolated. With require-corp, every cross-origin resource the page loads must allow it (CORS or Cross-Origin-Resource-Policy).

Console warning about the application/wasm MIME type

Section titled “Console warning about the application/wasm MIME type”
`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower.

Cause. The server sends .wasm files with another Content-Type.

Fix. Serve .wasm as application/wasm. It works either way; the fallback only compiles more slowly. If your bundler moves the files, pass their URL to init({ module_or_path }).

TypeScript errors from the dom-webcodecs types

Section titled “TypeScript errors from the dom-webcodecs types”

Cause. mediabunny, the optional dependency behind alpha2/mediabunny, installs @types/dom-webcodecs 0.1.13, whose declarations clash with TypeScript 5.9’s DOM library.

Fix. Compile with skipLibCheck, or pin the newer types in your package.json:

"overrides": { "@types/dom-webcodecs": "0.1.19" }

An app that imports alpha2/mediabunny also needs "ESNext.Disposable" in the lib of its tsconfig.json.

Cause. Browser export encodes with the browser’s WebCodecs encoders, and not every browser encodes every codec at every size.

Fix. Ask first: canEncodeVideoTrack("avc", { width, height, rate }) returns null when the browser does not encode it. Try vp9 in WebM, or export natively. The editor’s bridge.videoEncoders() does the same check.

Cause. The engine never reads system fonts. It draws text with the font files it was given, matched by font_family. A family no given font has draws in the fallback order: the first font that has the glyphs.

Fix. Give the renderer the font file, in the same order everywhere: fonts on the worker host or addFontFile in the browser, --font on the CLI, fonts in Node.js and Python. A native export lists the families it could not match in unmatchedFontFamilies. A family matches any name in the font’s name table, in any language, ignoring case.

MISSING_INPUT: the project shows text, but no fonts were registered

Section titled “MISSING_INPUT: the project shows text, but no fonts were registered”

Cause. The frame shows text or captions and no font was given at all.

Fix. Pass at least one font file, as above.

Text breaks onto different lines in the preview and the export

Section titled “Text breaks onto different lines in the preview and the export”

Cause. The two renderers have different fonts, or the same fonts in a different order.

Fix. Use the same files in the same order. With the same font bytes, the browser’s WasmTextRasterizer and a native export draw the same text.

A browser export stops on waiting tickets or missingSources

Section titled “A browser export stops on waiting tickets or missingSources”

Cause. An export frame needs source frames the engine doesn’t have. beginExportFrame() returns a waiting ticket naming them (missingSources, missingFrames) instead of rendering.

Fix. Upload the frames it names and ask again: the export continues at the same frame. exportToSink calls your refill with them. A frame still waiting after four refills fails with RESOURCE_LIMIT at stage sources-not-held: the refill did not upload what was asked, or the uploads did not fit the frame budget. refill must use a DecoderRefillCoordinator made for the export, not the preview’s.

MISSING_INPUT or CONFORM_FAILED from a native export

Section titled “MISSING_INPUT or CONFORM_FAILED from a native export”

Cause. A file the render needs was not given (MISSING_INPUT: an asset, an effect resource, a font or a frame), or a given file is offline or isn’t the media the project recorded (CONFORM_FAILED).

Fix. Give every source an --asset <source-id>=<path> (assets in Node.js and Python). alpha2-host conform reports, per source, what it found and what blocks, without rendering. An offline file’s message names the path the host looked up.

H.264 export fails with INVALID_INPUT on a server or on Windows N

Section titled “H.264 export fails with INVALID_INPUT on a server or on Windows N”

Cause. The FFmpeg in the release archives is LGPL and has no software H.264 encoder. H.264 comes from the GPU’s encoder (Vulkan Video, NVENC, VideoToolbox, Media Foundation, D3D12) or from OpenH264. A CPU-only server, an arm64 server, an NVIDIA datacenter GPU, or Windows N/KN without the Media Feature Pack has none.

Fix.

  • Install Cisco’s OpenH264: npx @alpha2-sh/node install --openh264 or python -m alpha2 install --openh264.
  • Or export VP9 or AV1, which the runtime encodes on the CPU: --video-codec vp9.
  • capabilities reports encode.h264.status with a reason and a remedy before you export.

Cause. An export never replaces a file unless asked.

Fix. Pass --overwrite (overwrite: true). It replaces the file only once the export is whole. OUTPUT_IN_USE means another running export is writing the same output.

Cause. The export’s working set doesn’t fit the memory the machine or container gives the host, or the kernel’s out-of-memory killer ended it.

Fix. Run fewer exports at once (concurrency), lower the memory budgets, or give the container more memory. failure.stage is machine-memory or memory-limit-reached when the machine refused it.

Cause. A browser download carries the quarantine attribute, and Gatekeeper does not accept the unpacked programs.

Fix. xattr -dr com.apple.quarantine <unpacked dir>, or download with curl -LO, or install with npx @alpha2-sh/node install. An OpenH264 library downloaded with a browser needs xattr -d com.apple.quarantine <library>.

Cause. The client looked for alpha2-host in the hostPath option, ALPHA2_HOST_PATH, the package, the cache and PATH, and found none.

Fix. Run npx @alpha2-sh/node install (or python -m alpha2 install), or point ALPHA2_HOST_PATH at an unpacked archive’s bin/alpha2-host.

Cause. The system is musl-based (Alpine) or its glibc is older than 2.35.

Fix. Use a glibc 2.35 or later base, such as node:22-slim or Ubuntu 22.04. No retry mends it.

Cause. Something held the host before it ran: a Gatekeeper check, an antivirus scan, or (HOST_BLOCKED) a Windows policy such as Smart App Control, App Control or AppLocker.

Fix. Allow the program, or raise hostStartTimeoutMs (Node.js) or host_start_timeout (Python) for a slow first scan.

A document the engine refuses fails to load with a message that names the problem. The same check runs everywhere: validateProject(project) in alpha2/project returns the problems as strings before you load, and alpha2.validate_project does it in Python. Some messages:

Message Cause Fix
clips a and b overlap without a covering transition on track main One track shows one clip at a time. Move one clip to another track, or add a transition over the overlap.
clip inset references unknown source nope A source_id names no source. Fix the id, or add the source.
missing field 'mode' An animatable value was written bare, such as "scale": { "x": 1, "y": 1 }. Wrap it: { "mode": "constant", "value": { "x": 1, "y": 1 } }.
unsupported schema version 2 The document is for another engine version. Use schema_version 1 with alpha2 0.5.
has unknown field "float" A field the schema doesn’t have, often a typo. Check the field against the schema reference.

A project that loads can still have lint issues, which lintProject (alpha2.lint_project) reports without refusing: off_frame_boundary for a time between frames, unreached_keyframe for a keyframe no frame reaches (often one written in the wrong time base).