evanw/esbuild · error
Cannot compute relative path from %q to %q
Error message
Cannot compute relative path from %q to %q
What it means
Returned by internalContext.Serve when ctx.realFS.Rel(servedir, AbsOutputDir) fails (ok=false). esbuild needs to compute the output directory relative to the serve directory to correctly URL-map served files; if the filesystem layer cannot relativize the two paths (e.g. cross-volume, or a path resolution failure), it gives up with this error. This is distinct from the 'must be contained' error — here the rel computation itself failed.
Source
Thrown at pkg/api/serve_other.go:791
// Stuff related to the output directory only matters if there are entry points
outdirPathPrefix := ""
if len(ctx.args.entryPoints) > 0 {
// Don't allow serving when builds are written to stdout
if ctx.args.options.WriteToStdout {
what := "entry points"
if len(ctx.args.entryPoints) == 1 {
what = "an entry point"
}
return ServeResult{}, fmt.Errorf("Cannot serve %s without an output path", what)
}
// Compute the output path prefix
if serveOptions.Servedir != "" && ctx.args.options.AbsOutputDir != "" {
// Make sure the output directory is contained in the "servedir" directory
relPath, ok := ctx.realFS.Rel(serveOptions.Servedir, ctx.args.options.AbsOutputDir)
if !ok {
return ServeResult{}, fmt.Errorf(
"Cannot compute relative path from %q to %q\n", serveOptions.Servedir, ctx.args.options.AbsOutputDir)
}
relPath = strings.ReplaceAll(relPath, "\\", "/") // Fix paths on Windows
if relPath == ".." || strings.HasPrefix(relPath, "../") {
return ServeResult{}, fmt.Errorf(
"Output directory %q must be contained in serve directory %q",
prettyPrintPath(ctx.realFS, ctx.args.options.AbsOutputDir),
prettyPrintPath(ctx.realFS, serveOptions.Servedir),
)
}
if relPath != "." {
outdirPathPrefix = relPath
}
}
}
// Determine the host
var listener net.ListenerView on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Place the output directory on the same volume/drive as the serve directory.
- Verify both Servedir and outdir exist and are absolute before calling Serve().
- On Windows, match drive letters / UNC hosts for both paths.
- If outdir is auto-derived, override it to live under servedir.
Example fix
// before (cross-volume)
ctx.Serve({ Servedir: '/mnt/www' }); // outdir on /dev/shm/build
// after (same volume)
mv /dev/shm/build /mnt/www/build // or set outdir under servedir
ctx = await api.Context({ ..., outdir: '/mnt/www/build' });
ctx.Serve({ Servedir: '/mnt/www' }); Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
function sameVolume(a, b) { /* compare volume root of resolved paths */ }
if (Servedir && outdir && !sameVolume(Servedir, outdir)) throw new Error('cross-volume'); Try / catch
try { await ctx.Serve({ Servedir }); } catch (e) { if (/Cannot compute relative path/.test(e.message)) { /* move outdir under servedir, same volume */ } throw e; } Prevention
- Keep outdir and servedir on the same volume.
- Ensure both paths exist and are absolute.
- On Windows, match drive letters / UNC hosts.
- Validate path relativization before Serve().
When it happens
Trigger: Serve() is called with a Servedir and the context has an AbsOutputDir, but realFS.Rel(Servedir, AbsOutputDir) returns ok=false. Typically because the two paths are on different volumes/drives or one cannot be canonicalized, echoing the Rel failure in internal/fs/filepath.go.
Common situations: On Windows, servedir on C:\ and outdir on D:\; one path on a network mount and the other local; a path that fails to absolutize (nonexistent dir) feeding into Rel; cross-device builds where output is written to a separate mount.
Related errors
- Rel: can't make {targpath} relative to {basepath}
- Must specify both key and certificate for HTTPS
- Invalid serve path: %s
- Invalid fallback path: %s
- Invalid origin: %s
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/248a88498d73b8bb.json.
Report an issue: GitHub.