evanw/esbuild · error

Cannot serve %s without an output path

Error message

Cannot serve %s without an output path

What it means

Returned by internalContext.Serve when the build has entry points but options.WriteToStdout is true. Serving requires writing build output to actual files on disk so the HTTP server can serve them; writing to stdout produces no files. esbuild detects entry points + WriteToStdout and refuses to serve, since there would be nothing to serve. The message names 'an entry point' (singular) or 'entry points' (plural).

Source

Thrown at pkg/api/serve_other.go:783

	}

	// 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 6ff1d8b0d8)

Solutions

  1. Disable WriteToStdout when using serve mode — set an outdir or outfile instead.
  2. If you need both behaviors, use two separate esbuild contexts.
  3. Check your config for stdout output flags before calling Serve().
  4. Ensure options.Write is true and an outdir is set for served builds.

Example fix

// before
ctx = await api.Context({ entryPoints: ['src/index.js'], write: false, stdout: true });
ctx.Serve({ servedir: './www' }); // -> Cannot serve ... without an output path

// after
ctx = await api.Context({ entryPoints: ['src/index.js'], outdir: './www', write: true });
ctx.Serve({ servedir: './www' });
Defensive patterns

Strategy: validation

Validate before calling

if (opts.entryPoints?.length && opts.writeToStdout) {
  throw new Error('Cannot serve with stdout output; set outdir instead');
}

Type guard

function isStdoutServeError(e) { return /Cannot serve .* without an output path/.test(e?.message || ''); }

Try / catch

try { await ctx.Serve(opts); } catch (e) { if (isStdoutServeError(e)) { delete opts.writeToStdout; opts.outdir = './dist'; /* recreate context */ } throw e; }

Prevention

When it happens

Trigger: A context configured with entry points and WriteToStdout:true (e.g. from --log-plugin or a stdout output config), then ctx.Serve() is called. The check at serve_other.go:778 sees WriteToStdout and returns the error.

Common situations: Configuring esbuild to emit to stdout (sometimes done for piping) and also trying to run serve mode; leftover WriteToStdout:true from a different use case; a wrapper that sets stdout output and then starts a dev server.

Related errors


AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03). Data as JSON: /data/errors/2a021f9b41b7cd5c.json. Report an issue: GitHub.