Guides

* [Getting started](/developers)
* [Projects and storage](/developers/projects-and-storage)
* [Media, fonts and models](/developers/media)
* [Save and load](/developers/save-and-load)
* [Theme, features and events](/developers/theming-and-events)
* [Driving the engine](/developers/engine)
* [Limits and support](/developers/limits-and-support)
* [Troubleshooting](/developers/troubleshooting)

More

* [Reference](/developers/reference/)
* [Everything as one text file](/developers/llms-full.txt)

# Troubleshooting

Each entry has the symptom, the cause and the fix. Search this page for the text in your console.

## Vite build fails with "UMD and IIFE output formats are not supported for code-splitting builds"

Cause: the engine's workers load their code in chunks, and Vite's default worker format cannot emit chunks.

Fix: set the worker format to ES modules in `vite.config.ts`.

```ts
import { defineConfig } from "vite";

export default defineConfig({
  worker: { format: "es" },
});

```

## Vite dev server fails to load the export or transcode worker

The console shows `Transcode worker error` or `does not provide an export named 'default'`, and the export silently runs on the main thread.

Cause: the dev server serves a worker from `node_modules` and resolves one of its dependencies to a CommonJS file that was not pre-bundled. Version 0.1.0 on Vite 5.4.21 does not show this; an earlier build did.

Fix: name the dependency from the error message in `optimizeDeps`.

```ts
import { defineConfig } from "vite";

export default defineConfig({
  worker: { format: "es" },
  optimizeDeps: { include: ["pixi.js"] },
});

```

## Fonts return 404 in Next.js

The console shows a 404 for `/fonts/Inter-Regular.woff2` and `[FontRegistry] Failed to load font "Inter"`.

Cause: text tracks load fonts from `/fonts/`, and nothing puts them there.

Fix: copy the fonts into the public folder once.

```
cp -r node_modules/@vidstudio/engine/assets/fonts public/fonts

```

Or serve them elsewhere and pass `options={{ assets: { fonts: "https://static.example.com/fonts/" } }}`, ending in a slash.

## Models return 404

The console shows a 404 for `/models/onnx-community/whisper-base.en/config.json` when a transcription starts.

Cause: the speech models are not in the package; they are fetched once by a script.

Fix: run the script, or turn captions off.

```
npx vidstudio-fetch-models public/models

```

Or pass `options={{ assets: { models: "https://static.example.com/models/" } }}`, or pass `features={{ captions: false }}` so no model is ever requested.

## The mark is drawn on a licensed domain

The preview and the exports carry the "vidstudio.app" mark although you passed a key.

Cause: one of five things, listed in the table.

| Cause                              | How to tell                                                                  | Fix                                                                                 |
| ---------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Old browser                        | Chrome before 137, Safari before 17, Firefox before 129 cannot check Ed25519 | Use a newer browser                                                                 |
| Plain http:// on a network address | window.isSecureContext is false, so WebCrypto is missing                     | Serve over HTTPS; only localhost is secure without it                               |
| Domain mismatch                    | The key covers example.com and the page is on example.org                    | Ask for a key that lists the page's domain; subdomains and www. are covered already |
| Name mismatch                      | licence.name differs from the name the key was issued to                     | Pass the exact name you were given                                                  |
| Expired                            | The key's end date has passed                                                | Ask for a new key                                                                   |

Add this function to your page and call it with your licence to see which one it is.

```ts
import { checkLicence, readLicenceKey } from "@vidstudio/engine";

export async function inspectLicence(licence: { name: string; key: string }): Promise<void> {
  console.log(await readLicenceKey(licence.key));
  console.log(await checkLicence(licence, location.hostname));
}

```

`readLicenceKey` returns `null` when the signature or the format is wrong, otherwise the name, domains and end date. `checkLicence` returns the state for the host.

## Transcription is slow

A minute of speech takes about twice as long as expected.

Cause: without the cross-origin isolation headers the speech runtime runs on one thread.

Fix: send both headers from your server. Then every cross-origin resource the page loads must send `Cross-Origin-Resource-Policy: cross-origin` too.

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

```

Without the headers everything still works; only transcription is slower.

## An import or export fails with "would exceed its storage quota"

The backend emits a `storage-full` event and the operation rejects.

Cause: the browser gave this origin less storage than the file needs. A private window and a Playwright context without a persistent profile get a very small quota.

Fix: free space on the device, or use a normal window. Delete finished exports with `discardExportFile`. In Playwright, use `launchPersistentContext`.

## `importFromUrl` rejects with `import-failed`

The address is correct and opens in a tab, but the import fails.

Cause: the file is on another origin and that server does not allow your page to read it.

Fix: have the server send `Access-Control-Allow-Origin` with your origin, or `*`. With the isolation headers on your page, it must also send `Cross-Origin-Resource-Policy: cross-origin`.

## Server rendering fails with "navigator is not defined"

Next.js, or another server renderer, throws `ReferenceError: navigator is not defined` when a page imports `@vidstudio/editor`.

Cause: the editor's rendering library reads the browser at module load time, and there is no browser on the server.

Fix: load the editor only in the browser, inside an effect.

```tsx
import { useEffect, useRef } from "react";
import type { MountedEditor, VidstudioEditorProps } from "@vidstudio/editor";

export function ClientEditor({ store, projectId }: Pick<VidstudioEditorProps, "store" | "projectId">) {
  const element = useRef<HTMLDivElement>(null);
  useEffect(() => {
    let editor: MountedEditor | null = null;
    import("@vidstudio/editor").then(({ mountEditor }) => {
      if (element.current) editor = mountEditor(element.current, { store, projectId });
    });
    return () => editor?.unmount();
  }, [store, projectId]);
  return <div ref={element} style={{ height: "100vh" }} />;
}

```

In Next.js, `dynamic(() => import("./Editor"), { ssr: false })` does the same for a component file that imports the package at the top.

## Two editors on one page show each other's media

Importing into one editor adds the clip to the other, or deleting in one removes from both.

Cause: both editors use the same namespace, so they share one database and one file folder.

Fix: give each editor its own namespace, in the store and in the options.

```ts
import { createStore } from "@vidstudio/editor";

export async function twoStores() {
  const left = await createStore({ namespace: "left" });
  const right = await createStore({ namespace: "right" });
  return {
    left: { store: left, options: { namespace: "left" } },
    right: { store: right, options: { namespace: "right" } },
  };
}

```

Pass each pair as the `store` and `options` props of its editor.

## A notice sits over the timeline

A bar in the lower left of the editor reads "This editor is unlicensed for this domain, so its picture and exports carry a watermark."

Cause: the licence state is `"invalid"` on this host. On localhost there is no notice.

Fix: pass a key that covers the domain. The user can dismiss the bar with its close button; it comes back on the next mount.

## Export rejects with `missing-media`

`exportProject` rejects with the message `"<file>" is missing. Remove its clips or open the project with the file before exporting.`

Cause: when the project was loaded, the resolver threw or the download failed for that asset, so it loaded with `missing: true`.

Fix: load the document again with a resolver that returns the file, or delete the clips that play it. `getMediaAssets()` lists the assets; the missing ones have `missing: true`.

## A warning about a Canvas 2D fallback in headless Chromium

The console shows `PixiJS WebGL init failed` followed by `using Canvas 2D fallback`.

Cause: headless Chromium has no WebGL unless it is launched with a software renderer, so the preview falls back to Canvas 2D.

Fix: nothing is broken; the frames are the same. To silence it, pass `options={{ renderer: "canvas2d" }}` in automation.

---
Source: [https://vidstudio.app/developers/troubleshooting](https://vidstudio.app/developers/troubleshooting)
