evanw/esbuild · error

Invalid serve path

Error message

Invalid serve path: %s

What it means

The servedir option for serve mode must be resolvable to an absolute path by the filesystem provider. This error fires when ctx.realFS.Abs(serveOptions.Servedir) fails, indicating the path is invalid or unresolvable from the current working directory.

Solutions

  1. Verify the servedir path exists and is accessible before starting serve mode
  2. Use an absolute path resolved via path.resolve() or filepath.Abs()
  3. Check directory read permissions if the path should exist

Example fix

// before
esbuild.serve({ servedir: './nonexistent-dir' })
// after
import fs from 'fs'
if (!fs.existsSync('./public')) throw new Error('servedir missing')
esbuild.serve({ servedir: path.resolve('./public') })
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs'
import path from 'path'
function validateServedir(servedir) {
  const abs = path.resolve(servedir)
  if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
    throw new Error(`servedir does not exist or is not a directory: ${abs}`)
  }
  return abs
}
serveOptions.servedir = validateServedir(serveOptions.servedir)

Prevention

When it happens

Trigger: Passing a servedir that does not exist, has invalid characters, or is on an inaccessible volume, causing Abs() to fail.

Common situations: Pointing servedir to a deleted or typo'd directory name, a path with permission issues, or a relative path that cannot be resolved because the process working directory is gone.

Related errors


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

Appendix: source

Thrown at pkg/api/serve_other.go:771

		return ServeResult{}, errors.New("Cannot serve a disposed context")
	}

	// Don't allow starting serve mode multiple times
	if ctx.handler != nil {
		return ServeResult{}, errors.New("Serve mode has already been enabled")
	}

	// Don't allow starting serve mode multiple times
	if (serveOptions.Keyfile != "") != (serveOptions.Certfile != "") {
		return ServeResult{}, errors.New("Must specify both key and certificate for HTTPS")
	}

	// Validate the "servedir" path
	if serveOptions.Servedir != "" {
		if absPath, ok := ctx.realFS.Abs(serveOptions.Servedir); ok {
			serveOptions.Servedir = absPath
		} else {
			return ServeResult{}, fmt.Errorf("Invalid serve path: %s", serveOptions.Servedir)
		}
	}

	// Validate the "fallback" path
	if serveOptions.Fallback != "" {
		if absPath, ok := ctx.realFS.Abs(serveOptions.Fallback); ok {
			serveOptions.Fallback = absPath
		} else {
			return ServeResult{}, fmt.Errorf("Invalid fallback path: %s", serveOptions.Fallback)
		}
	}

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

View on GitHub (pinned to f6058f8364)