evanw/esbuild · error
Cannot compute relative path from
Error message
Cannot compute relative path from %q to %q
What it means
When both servedir and outdir are set in serve mode, esbuild computes a relative path from servedir to outdir using filepath.Rel(). This error fires when that computation fails, which can happen when the two paths are on different volumes (e.g. different drive letters on Windows).
Solutions
- Ensure servedir and outdir are on the same drive or volume
- Place outdir inside or adjacent to servedir
- Use an absolute outdir that shares a common prefix with servedir
Example fix
// before (Windows)
esbuild.serve({ servedir: 'C:\\serve' }) // outdir: D:\out
// after
esbuild.serve({ servedir: 'C:\\serve' }) // outdir: C:\\serve\out Defensive patterns
Strategy: validation
Validate before calling
import path from 'path'
function validateServeOutdir(servedir, outdir) {
const absServe = path.resolve(servedir)
const absOut = path.resolve(outdir)
// On Windows, check same drive letter
if (process.platform === 'win32') {
const serveDrive = absServe.substring(0, 2)
const outDrive = absOut.substring(0, 2)
if (serveDrive.toLowerCase() !== outDrive.toLowerCase()) {
throw new Error(`servedir (${absServe}) and outdir (${absOut}) must be on the same drive`)
}
}
}
validateServeOutdir(serveOptions.servedir, buildOptions.outdir) Prevention
- Keep servedir and outdir on the same filesystem volume or drive
- Place outdir inside or adjacent to servedir
- On Windows, verify both paths share the same drive letter
When it happens
Trigger: Setting servedir and outdir to paths on different filesystem volumes or drives, making a relative path between them impossible to compute.
Common situations: On Windows, placing servedir on C:\ and outdir on D:\, or on Linux/macOS using paths that span different mount points in a way filepath.Rel cannot bridge.
Related errors
- Invalid fallback path
- Invalid serve path
- Output directory must be contained in serve directory
- The working directory
- Cannot serve a disposed context
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/248a88498d73b8bb.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/serve_other.go:808
// 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 f6058f8364)