neoclide/coc.nvim · error

unable to watch

Error message

unable to watch

What it means

After capability checks pass, Watchman.createClient calls watchProject(root); if watchman cannot establish a watch on the given root (watchProject returns falsy), it throws 'unable to watch'. The partially constructed client is disposed before rethrowing.

Source

Thrown at src/core/watchman.ts:162

      this.client.end()
      this.client = undefined
    }
  }

  private appendOutput(message: string, type = "Info"): void {
    if (this.channel) {
      this.channel.appendLine(`[${type}  - ${(new Date().toLocaleTimeString())}] ${message}`)
    }
  }

  public static async createClient(binaryPath: string, root: string, channel?: OutputChannel): Promise<Watchman> {
    let watchman: Watchman
    try {
      watchman = new Watchman(binaryPath, channel)
      let valid = await watchman.checkCapability()
      if (!valid) throw new Error('required capabilities do not exist.')
      let watching = await watchman.watchProject(root)
      if (!watching) throw new Error('unable to watch')
      return watchman
    } catch (e) {
      if (watchman) watchman.dispose()
      throw e
    }
  }
}

View on GitHub (pinned to 50e974d969)

Solutions

  1. Verify the root path exists and is a readable directory before calling createClient.
  2. Check .watchmanconfig and watchman's ignore rules for exclusions of the path.
  3. Run 'watchman watch-project <root>' manually to see the underlying watchman error.
  4. Ensure the directory is on a local filesystem watchman supports (not a network mount).

Example fix

// before
let wm = await Watchman.createClient(watchmanPath, '/mnt/network/project') // 'unable to watch'
// after
if (fs.existsSync('/home/user/project')) {
  let wm = await Watchman.createClient(watchmanPath, '/home/user/project')
}
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs')
if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
  throw new Error(`Cannot watch non-directory root: ${root}`)
}

Try / catch

try {
  const wm = await Watchman.createClient(binaryPath, root)
} catch (e) {
  if (e.message === 'unable to watch') {
    logger.warn(`watchman cannot watch ${root}; falling back to fs watcher`)
    return fallbackWatcher(root)
  } else throw e
}

Prevention

When it happens

Trigger: Watchman.createClient(binaryPath, root) where watchman.watchProject(root) resolves false — typically because root does not exist, is not readable, is excluded by watchman config (.watchmanconfig ignore), or watchman refuses the path.

Common situations: Passing a deleted or symlinked-but-broken directory as root; project on a network mount watchman cannot watch; watchman's ignore list excludes the folder; permissions issues on the directory.

Related errors


AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31). Data as JSON: /api/errors/3812d608706d2b43. Report an issue: GitHub.