microsoft/typescript-go · warning
failed to register file watcher: %w
Error message
failed to register file watcher: %w
What it means
WatchFiles (server.go:247-254) failed at the first branch: the server is running its builtin in-process file watcher (used when the client lacks dynamic registration support but the platform — Windows or FSEvents — supports efficient recursive watching) and the watcher backend rejected the registration of the given watcher id and FileSystemWatcher patterns. The error wraps the underlying watcher error with %w.
Source
Thrown at internal/lsp/server.go:250
projectProgress *projectLoadingProgress
startWatchdog func(parentPID int)
flakeLogging lsproto.DiagnosticFlakeLogLevel
}
func (s *Server) Session() *project.Session { return s.session }
// InitComplete returns a channel that is closed when the server has finished
// processing the initialized notification, including the initial configuration
// exchange with the client.
func (s *Server) InitComplete() <-chan struct{} { return s.initComplete }
// WatchFiles implements project.Client.
func (s *Server) WatchFiles(ctx context.Context, id project.WatcherID, watchers []*lsproto.FileSystemWatcher) error {
if s.builtinWatcher != nil {
if err := s.builtinWatcher.WatchFiles(string(id), watchers); err != nil {
return fmt.Errorf("failed to register file watcher: %w", err)
}
s.watchers.Add(id)
return nil
}
_, err := sendClientRequest(ctx, s, lsproto.ClientRegisterCapabilityInfo, &lsproto.RegistrationParams{
Registrations: []*lsproto.Registration{
{
Id: string(id),
RegisterOptions: &lsproto.RegisterOptions{
WorkspaceDidChangeWatchedFiles: &lsproto.DidChangeWatchedFilesRegistrationOptions{
Watchers: watchers,
},
},
},
},
})
if err != nil {
return fmt.Errorf("failed to register file watcher: %w", err)View on GitHub (pinned to 1bcfa18d79)
Solutions
- Read the wrapped cause — it is the watcher backend's error (pattern parse failure, limit, permissions) and dictates the fix.
- Raise the OS watch budget (e.g. fs.inotify.max_user_watches / max_user_instances on Linux) or reduce the number/width of watched globs.
- Validate watcher glob patterns (glob syntax supported by the backend) before passing them in FileSystemWatcher entries.
- If watching is not needed, disable watchEnabled/watcher setup so WatchFiles is not called.
Example fix
// before: overly broad watchers
watchers := []*lsproto.FileSystemWatcher{{ GlobPattern: new("**/*") }}
// after: scope to source files
watchers := []*lsproto.FileSystemWatcher{{ GlobPattern: new("**/*.{ts,tsx,js,jsx}") }} Defensive patterns
Strategy: try-catch
Validate before calling
// before registering, sanity-check glob patterns
for _, w := range watchers {
if w.GlobPattern == nil || *w.GlobPattern == "" {
return fmt.Errorf("watcher glob required")
}
if _, err := path.Match(*w.GlobPattern, "x.ts"); err != nil {
return fmt.Errorf("bad glob %q: %w", *w.GlobPattern, err)
}
} Type guard
func watcherGlobsValid(watchers []*lsproto.FileSystemWatcher) bool {
for _, w := range watchers {
if w.GlobPattern == nil || *w.GlobPattern == "" {
return false
}
}
return true
} Try / catch
if err := client.WatchFiles(ctx, id, watchers); err != nil {
if strings.Contains(err.Error(), "failed to register file watcher") {
// log and degrade: continue without watching; edits rely on didChange events
log.Printf("file watching unavailable: %v", err)
} else {
return err
}
} Prevention
- Raise fs.inotify.max_user_watches / max_user_instances on Linux for large trees.
- Prefer narrow globs (source extensions) over '**/*'.
- Degrade gracefully: the language server can operate on didChange/didOpen notifications alone.
When it happens
Trigger: Server constructed with a builtin lspwatcher.Watcher and the OS-level watch could not be created: invalid glob pattern in a FileSystemWatcher, watch limits exhausted (inotify/fsevents), the watched path does not exist, or the platform backend errored. The call site is project.Client.WatchFiles during project loading when file watching is enabled.
Common situations: Linux hosts hitting inotify watch limits on large monorepos; Windows/FSEvents path edge cases; malformed watcher globs from configuration; running many server instances against the same tree.
Related errors
- no file watcher exists with ID %s
- failed to unregister file watcher: %w
- Invalid value for ${name}: ${value}
- forRelease requires setPrerelease unless nativePreviewReleas
- Language client is not initialized
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/8347d4a1d117f0f6.
Report an issue: GitHub.