evanw/esbuild · error

Cannot serve without an output path

Error message

Cannot serve %s without an output path

What it means

When using serve mode with entry points, esbuild needs a real output directory to write build artifacts that the server can serve. This error fires when the build is configured to write to stdout (WriteToStdout is true) instead of an output directory. The message distinguishes between 'an entry point' (singular) and 'entry points' (plural).

Solutions

  1. Set an output directory (outdir) in the build options when using serve mode with entry points
  2. Remove any stdout-redirecting options such as write:false or stdout-format output
  3. Do not use entry points with serve mode if you only need to serve static files (use servedir alone)

Example fix

// before
esbuild.build({ entryPoints: ['app.ts'], write: false })
esbuild.serve({ servedir: 'public' })
// after
esbuild.build({ entryPoints: ['app.ts'], outdir: 'public/dist' })
esbuild.serve({ servedir: 'public' })
Defensive patterns

Strategy: validation

Validate before calling

function validateServeConfig(buildOptions) {
  if (buildOptions.entryPoints?.length > 0) {
    if (!buildOptions.outdir) {
      throw new Error('outdir is required when using serve mode with entry points')
    }
    if (buildOptions.write === false) {
      throw new Error('write:false is not compatible with serve mode and entry points')
    }
  }
}
validateServeConfig(buildOptions)

Prevention

When it happens

Trigger: Starting serve mode with one or more entry points while the build writes output to stdout (e.g. using --outfile=/dev/stdout, stdout targeting, or write:false without a proper outdir).

Common situations: Combining serve mode with a build config designed for piping output (e.g. esbuild --bundle --serve without --outdir), or reusing a programmatic build config that had stdout output.

Related errors


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/2a021f9b41b7cd5c. Report an issue: GitHub.

Appendix: source

Thrown at pkg/api/serve_other.go:800

	}

	// Validate the CORS origins
	for _, origin := range serveOptions.CORS.Origin {
		if star := strings.IndexByte(origin, '*'); star >= 0 && strings.ContainsRune(origin[star+1:], '*') {
			return ServeResult{}, fmt.Errorf("Invalid origin: %s", origin)
		}
	}

	// 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),
				)
			}

View on GitHub (pinned to f6058f8364)