remotion-dev/remotion · error · Error
Unexpected build output path
Error message
Unexpected build output path: ${output.path} What it means
The promo-pages bundle script copies every esbuild build output into the dist/ directory, but first normalizes the output path and rejects any file that resolves outside dist/. If a relative output path still starts with '../' after stripping the 'dist/' prefix, the build fails fast rather than writing files outside the intended output directory.
Solutions
- Check the esbuild config in bundle.ts: set `outbase` (usually the source root) so all outputs land under dist/ without '../' segments.
- Move entry points so they all live below the directory used as outbase.
- Log output.path (console.log(output.path)) right before the throw to see which file escapes and fix its entry/asset config.
- If the file genuinely must live outside dist/, copy it explicitly after the build instead of routing it through esbuild outputs.
Example fix
// before
await esbuild.build({ entryPoints: ['./src/index.ts', '../shared/entry.ts'], outdir: 'dist' });
// after
await esbuild.build({ entryPoints: ['./src/index.ts', './src/shared-entry.ts'], outdir: 'dist', outbase: 'src' }); Defensive patterns
Strategy: validation
Validate before calling
// pre-validate the esbuild config mapping
const outbase = 'src';
for (const entry of entryPoints) {
const rel = path.relative(outbase, entry);
if (rel.startsWith('..')) throw new Error(`Entry outside outbase: ${entry}`);
} Try / catch
try {
await build();
} catch (e) {
if (String(e.message).startsWith('Unexpected build output path')) {
console.error('Fix esbuild outbase/outdir so outputs stay under dist/', e.message);
process.exit(1);
}
throw e;
} Prevention
- Always set an explicit outbase covering all entry points.
- Add a CI check that no esbuild output path contains '..'.
- Keep entry points within a single source root directory.
When it happens
Trigger: Running the bundle script (bun packages/promo-pages/bundle.ts or its build pipeline) when esbuild emits an output file whose resolved path escapes dist/, e.g. a chunk or asset with an outbase/outdir misconfiguration producing paths like '../shared/foo.js'.
Common situations: Misconfigured esbuild `outbase` after moving entry points; adding a new entry point in a parent directory; changing `outdir` so emitted chunk paths contain '..'; symlinked or nested entry files changing relative path computation.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Error in remotion.config.ts file
- No output files found in the config file.
- Browser Studio vendor entry was not generated
- Caching flag must be a boolean.
- Cannot call `getInputProps()` - window.remotion_inputProps…
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/874fa9e30a4d55fb.
Report an issue: GitHub.
Appendix: source
Thrown at packages/promo-pages/bundle.ts:94
for (const result of results) {
if (!result.success) {
console.log(result.logs.join('\n'));
process.exit(1);
}
for (const output of result.outputs) {
// On Windows, Bun may return absolute output paths here. Normalize them back
// into the local dist directory so we don't accidentally write invalid paths.
const relativeOutputPath = path.isAbsolute(output.path)
? path.relative(outdir, output.path)
: output.path;
const normalizedOutputPath = relativeOutputPath.replaceAll('\\', '/');
const outputPathWithoutDistPrefix = normalizedOutputPath.startsWith('dist/')
? normalizedOutputPath.slice('dist/'.length)
: normalizedOutputPath;
if (outputPathWithoutDistPrefix.startsWith('../')) {
throw new Error(`Unexpected build output path: ${output.path}`);
}
await Bun.write(
path.join('dist', outputPathWithoutDistPrefix),
await output.text(),
);
}
}
export {};
View on GitHub (pinned to 46a3a6bf13)