microsoft/typescript-go · error · ErrClientError
%w: dir is required
Error message
%w: dir is required
What it means
startCPUProfile rejects params that are nil or have an empty Dir field. ProfileParams has a single string field dir; an omitted field decodes to the Go zero value "", which fails this check. The dir is where the server writes the pprof CPU profile file.
Source
Thrown at internal/api/session.go:871
return s.handleStopCPUProfile(ctx)
case string(MethodSaveHeapProfile):
return s.handleSaveHeapProfile(ctx, parsed.(*ProfileParams))
case string(MethodGetReferencesToSymbolInFile):
return s.handleGetReferencesToSymbolInFile(ctx, parsed.(*GetReferencesToSymbolInFileParams))
case string(MethodGetReferencedSymbolsForNode):
return s.handleGetReferencedSymbolsForNode(ctx, parsed.(*GetReferencedSymbolsForNodeParams))
case string(MethodGetSignatureUsages):
return s.handleGetSignatureUsages(ctx, parsed.(*GetSignatureUsagesParams))
case string(MethodGetCompletionsAtPosition):
return s.handleGetCompletionsAtPosition(ctx, parsed.(*GetCompletionsAtPositionParams))
default:
return nil, fmt.Errorf("unknown method: %s", method)
}
}
func (s *Session) handleStartCPUProfile(_ context.Context, params *ProfileParams) (any, error) {
if params == nil || params.Dir == "" {
return nil, fmt.Errorf("%w: dir is required", ErrClientError)
}
if err := s.cpuProfiler.StartCPUProfile(params.Dir); err != nil {
return nil, fmt.Errorf("%w: failed to start CPU profile: %w", ErrClientError, err)
}
return nil, nil
}
func (s *Session) handleStopCPUProfile(_ context.Context) (*ProfileResult, error) {
filePath, err := s.cpuProfiler.StopCPUProfile()
if err != nil {
return nil, fmt.Errorf("%w: failed to stop CPU profile: %w", ErrClientError, err)
}
return &ProfileResult{File: filePath}, nil
}
func (s *Session) handleSaveHeapProfile(_ context.Context, params *ProfileParams) (*ProfileResult, error) {
if params == nil || params.Dir == "" {
return nil, fmt.Errorf("%w: dir is required", ErrClientError)View on GitHub (pinned to 1bcfa18d79)
Solutions
- Pass a non-empty absolute directory path in the dir field
- Default the value client-side (e.g. os.TempDir()) before sending when no explicit dir is configured
Example fix
// before
conn.Call(ctx, string(api.MethodStartCPUProfile), api.ProfileParams{})
// after
conn.Call(ctx, string(api.MethodStartCPUProfile), api.ProfileParams{Dir: "/tmp/tsprofiles"}) Defensive patterns
Strategy: validation
Validate before calling
func profileParams(dir string) (api.ProfileParams, error) {
if dir == "" { dir = os.TempDir() }
if !filepath.IsAbs(dir) { dir, _ = filepath.Abs(dir) }
return api.ProfileParams{Dir: dir}, nil
} Type guard
func hasProfileDir(p *api.ProfileParams) bool {
return p != nil && p.Dir != ""
} Prevention
- Default the profile dir client-side (e.g. os.TempDir()) so it is never empty
- Send absolute paths to avoid cwd ambiguity on the server
When it happens
Trigger: Sending {} or null as params to startCPUProfile; omitting the dir key in the JSON payload; sending "dir": "" explicitly.
Common situations: Optional-looking params treated as skippable; client defaulting to empty string when a config knob (profile output directory) is unset.
Related errors
- %w: failed to start CPU profile: %w
- %w: failed to stop CPU profile: %w
- Cannot run a temporary file update on an inactive snapshot
- Snapshot is disposed
- Cannot create directory: a file already exists at "/${segmen
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/e60bb135dbd0b389.
Report an issue: GitHub.