windmill-labs/windmill · error
esbuild-wasm@${version} tarball did not contain lib/main.js
Error message
esbuild-wasm@${version} tarball did not contain lib/main.js What it means
Thrown by ensureWasmPackage after extracting the esbuild-wasm tarball: the extracted contents did not include lib/main.js, so the extracted package cannot be loaded as the esbuild JS host. The loader deletes the temp dir and refuses to cache the incomplete package. It guards against pointing WINDMILL_ESBUILD_WASM_URL at something that is not a valid esbuild-wasm npm-style tarball.
Source
Thrown at cli/src/utils/esbuild_loader.ts:143
log.info(`Downloading esbuild-wasm@${version} from ${url} ...`);
const res = await fetch(url);
if (!res.ok || !res.body) {
throw new Error(
`Failed to download esbuild-wasm@${version} (${res.status} ${res.statusText}). ` +
`Set WINDMILL_ESBUILD_WASM_PATH to an extracted esbuild-wasm package dir, ` +
`point WINDMILL_ESBUILD_WASM_URL at a reachable tarball, or repair the native esbuild install.`
);
}
// Extract to a unique temp dir and rename into place so a crash or a
// concurrent writer can't leave a half-extracted package behind, and so two
// extractions never share an in-progress directory.
const tmpDir = `${destDir}.${process.pid}.${extractCounter++}.tmp`;
fs.rmSync(tmpDir, { recursive: true, force: true });
await extractTarball(res.body, tmpDir);
if (!fs.existsSync(path.join(tmpDir, "lib", "main.js"))) {
fs.rmSync(tmpDir, { recursive: true, force: true });
throw new Error(`esbuild-wasm@${version} tarball did not contain lib/main.js`);
}
try {
fs.renameSync(tmpDir, destDir);
} catch {
// Another process won the race, or rename across devices failed; clean up
// and let the existsSync check below decide whether the cache is usable.
fs.rmSync(tmpDir, { recursive: true, force: true });
}
if (!fs.existsSync(path.join(destDir, "lib", "main.js"))) {
throw new Error(`Failed to cache esbuild-wasm@${version} at ${destDir}`);
}
return destDir;
}
/**
* Resolves a tar entry to an absolute path inside destDir, stripping the leading
* "package/" component that npm tarballs use. Returns null if the entry would
* escape destDir (tar-slip), since WINDMILL_ESBUILD_WASM_URL allows untrustedView on GitHub (pinned to e474e8803c)
Solutions
- Point WINDMILL_ESBUILD_WASM_URL at the official npm tarball layout, e.g. https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-<version>.tgz.
- Verify the artifact: `tar tzf file.tgz | grep lib/main.js` must list package/lib/main.js.
- Set WINDMILL_ESBUILD_WASM_PATH to a correctly extracted esbuild-wasm package directory instead of relying on a URL.
- Re-upload/fix the artifact in your internal mirror if it is truncated or the wrong package.
Example fix
// before WINDMILL_ESBUILD_WASM_URL=https://github.com/evanw/esbuild/archive/refs/tags/v0.28.0.tar.gz // after: use the npm-style package tarball WINDMILL_ESBUILD_WASM_URL=https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.28.0.tgz
Defensive patterns
Strategy: validation
Validate before calling
import { execSync } from "node:child_process";
const url = process.env.WINDMILL_ESBUILD_WASM_URL;
if (url) {
const out = execSync(`tar tzf <(curl -fsSL ${url}) 2>/dev/null || curl -fsSL ${url} | tar tz`, { shell: "/bin/bash" }).toString();
if (!out.split("\n").some((n) => /(^|\/)lib\/main\.js$/.test(n.replace(/^package\//, "")))) {
throw new Error(`Tarball at ${url} has no lib/main.js — use an esbuild-wasm npm package tarball`);
}
} Try / catch
try {
await getEsbuild();
} catch (e) {
if (String(e).includes("did not contain lib/main.js")) {
console.error("WINDMILL_ESBUILD_WASM_URL must point at an esbuild-wasm npm tarball (package/lib/main.js inside)");
}
throw e;
} Prevention
- Only point WINDMILL_ESBUILD_WASM_URL at npm-registry-style esbuild-wasm tarballs, not GitHub source archives.
- Validate mirrors with `tar tzf` and grep for package/lib/main.js before deploying.
- Pin the exact esbuild-wasm version tarball matching the CLI's esbuild pin.
- Prefer WINDMILL_ESBUILD_WASM_PATH with a manually extracted, verified package in air-gapped setups.
When it happens
Trigger: The tarball downloaded from WINDMILL_ESBUILD_WASM_URL (or a proxy-intercepted response) extracted successfully but has no lib/main.js at its root after stripping the leading package/ component — i.e. it is not an esbuild-wasm package tarball, is a wrong/truncated artifact, or has an unexpected inner layout.
Common situations: WINDMILL_ESBUILD_WASM_URL pointing at a GitHub archive, a wrong package's tarball, or an HTML error page saved as .tgz; an internal mirror serving an older tarball layout; a corrupted upload in a self-hosted mirror; a manually crafted tarball missing the package/ prefix the extractor strips.
Related errors
- Found ${wrongFormatPaths.length} directory(ies) using ${foun
- Could not find a workspace mapped to branch \`${opts.fromBra
- Could not resolve workspace from branch name. Make sure you
- Failed to download esbuild-wasm@${version} (${res.status} ${
- Failed to cache esbuild-wasm@${version} at ${destDir}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/c6fa05c49cb57972.
Report an issue: GitHub.