microsoft/typescript-go · critical

StdioServerOptions.Cwd is required

Error message

StdioServerOptions.Cwd is required

What it means

NewStdioServer panics with "StdioServerOptions.Cwd is required" when the options struct is constructed with an empty Cwd field. Cwd becomes SessionOptions.CurrentDirectory of the underlying project session, so it anchors every relative path (tsconfig resolution, file names, default library location) and cannot be empty. This is a fail-fast programmer-error check in the constructor: it crashes the process instead of returning an error.

Source

Thrown at internal/api/server.go:48

	// CollectTiming enables per-request server processing-time measurement.
	// When enabled, the server accumulates each request's processing time into
	// running totals and a recent-request ring buffer. Response messages are
	// left unchanged; the client folds this data into its own timing snapshot
	// on demand via getServerTiming / resetServerTiming requests.
	CollectTiming bool
}

// StdioServer runs an API session over STDIO using MessagePack protocol.
// This is the entry point for the synchronous STDIO-based API used by
// native TypeScript tooling integration.
type StdioServer struct {
	options *StdioServerOptions
}

// NewStdioServer creates a new STDIO-based API server.
func NewStdioServer(options *StdioServerOptions) *StdioServer {
	if options.Cwd == "" {
		panic("StdioServerOptions.Cwd is required")
	}

	return &StdioServer{
		options: options,
	}
}

// Run starts the server and blocks until the connection closes.
func (s *StdioServer) Run(ctx context.Context) error {
	var transport Transport
	if s.options.PipePath != "" {
		t, err := NewPipeTransport(s.options.PipePath)
		if err != nil {
			return fmt.Errorf("failed to create pipe transport: %w", err)
		}
		defer t.Close()
		transport = t
	} else {

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Set Cwd to the absolute path of the workspace root the server should treat as the project's current directory
  2. If Cwd comes from a flag/env var, validate it is non-empty before calling NewStdioServer and surface a proper error instead of the panic
  3. In tests, pass t.TempDir() or the test's working directory

Example fix

// before
srv := api.NewStdioServer(&api.StdioServerOptions{In: os.Stdin, Out: os.Stdout}) // panics

// after
cwd, _ := os.Getwd()
srv := api.NewStdioServer(&api.StdioServerOptions{In: os.Stdin, Out: os.Stdout, Cwd: cwd})
Defensive patterns

Strategy: validation

Validate before calling

// Go host code: validate before constructing the server.
if options.Cwd == "" {
    return fmt.Errorf("StdioServerOptions.Cwd is required: set it to the workspace root")
}
if !filepath.IsAbs(options.Cwd) {
    options.Cwd, _ = filepath.Abs(options.Cwd)
}
srv := api.NewStdioServer(options)

Try / catch

// Panics cannot be caught in Go; convert to an error path before construction:
func newServer(opts api.StdioServerOptions) (*api.StdioServer, error) {
    if strings.TrimSpace(opts.Cwd) == "" {
        return nil, errors.New("cwd must be set to the workspace root")
    }
    return api.NewStdioServer(&opts), nil
}

Prevention

When it happens

Trigger: Calling api.NewStdioServer(&api.StdioServerOptions{...}) without setting Cwd; building StdioServerOptions from a flag/env var that is empty because the flag was not parsed or the env var is missing; constructing a zero-valued StdioServerOptions and setting only In/Out streams.

Common situations: Embedding the typescript-go API server in a host process (LSP/tooling integration) and forgetting the working directory; tests that wire os.Stdin/os.Stdout but skip Cwd; a CLI where the cwd flag defaults to "" when the process is spawned without arguments; refactors that move server construction before cwd detection.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/922c4d15cb15832c. Report an issue: GitHub.