{"id":"fca864b6669f07a4","repo":"jestjs/jest","slug":"failed-to-start-watch-mode","errorCode":null,"errorMessage":"Failed to start watch mode.","messagePattern":"Failed to start watch mode\\.","errorType":"exception","errorClass":"AggregateError","httpStatus":null,"severity":"error","filePath":"packages/jest-haste-map/src/watchers/index.ts","lineNumber":84,"sourceCode":"      : FSEventsWatcher.isSupported()\n        ? (FSEventsWatcher as unknown as WatcherCtor)\n        : NodeWatcher;\n\n    const statCache = new Map<string, Stats>();\n    const results = await Promise.allSettled(\n      this._roots.map(root =>\n        this._createWatcher(Backend, root, onChange, statCache),\n      ),\n    );\n    const fulfilled = results\n      .filter(r => r.status === 'fulfilled')\n      .map(r => (r as PromiseFulfilledResult<IWatcher>).value);\n    const rejected = results\n      .filter(r => r.status === 'rejected')\n      .map(r => (r as PromiseRejectedResult).reason);\n    if (rejected.length > 0) {\n      await Promise.allSettled(fulfilled.map(w => w.close()));\n      throw new AggregateError(rejected, 'Failed to start watch mode.');\n    }\n    this._watchers = fulfilled;\n  }\n\n  async close(): Promise<void> {\n    await Promise.all(this._watchers.map(watcher => watcher.close()));\n    this._watchers = [];\n  }\n\n  private _createWatcher(\n    Backend: WatcherCtor,\n    root: string,\n    onChange: OnChangeCallback,\n    statCache: Map<string, Stats>,\n  ): Promise<IWatcher> {\n    const watcher = new Backend(root, {\n      dot: true,\n      glob: this._extensions.map(ext => `**/*.${ext}`),","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-haste-map/src/watchers/index.ts#L66-L102","documentation":"WatcherDriver.start() creates one watcher per root using Promise.allSettled; if any root's watcher creation rejects (constructor error or a 240s 'ready' timeout), it closes the watchers that did start and throws an AggregateError with message 'Failed to start watch mode.' whose errors array holds the per-root failures. A second, timeout-based throw with the same message exists at watchers/index.ts:116 for a single root that never emits 'ready' within MAX_WAIT_TIME (240s).","triggerScenarios":"Either: (a) one or more new Backend(root, opts) constructors throw (e.g. FSEventsWatcher on non-Darwin, or a permission error opening a root); or (b) a watcher's 'ready' event does not fire within 240s, triggering the setTimeout reject at line 113-117. Both surface as 'Failed to start watch mode.' — the AggregateError variant carries underlying reasons.","commonSituations":"Watched roots include a path that does not exist or is unreadable; a root is a network mount that never finishes the initial walk; too many inotify watchers on Linux (ENOSPC) causing NodeWatcher to fail; watchman daemon wedged so WatchmanWatcher never becomes ready; very large monorepo exceeding the 240s ready timeout.","solutions":["Inspect the AggregateError.errors array (or the inner Error for the timeout variant) for the real per-root cause.","Confirm every entry in roots exists and the Jest process has read permission on it.","On Linux, raise the inotify watcher limit: `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`.","For slow initial walks, reduce the watched surface (narrow roots, tighten ignorePattern) or prefer watchman (useWatchman:true) which returns ready faster via clock-based deltas.","If watchman is the culprit, run `watchman shutdown-server` then let Jest restart it, or set watchman:false to use NodeWatcher/FSEventsWatcher."],"exampleFix":"// before — watching a huge root that never becomes ready in 240s\nmodule.exports = { roots: ['<rootDir>'], watchPathIgnorePatterns: [] };\n\n// after — narrow what is watched and let watchman handle deltas\nmodule.exports = {\n  roots: ['<rootDir>/src', '<rootDir>/packages'],\n  watchPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/build/'],\n};","handlingStrategy":"try-catch","validationCode":"import {statSync} from 'node:fs';\nfor (const root of options.roots) {\n  statSync(root); // throws if a root is missing/unreadable — fix before watching\n}\n// On Linux, check inotify budget\nimport {readFileSync} from 'node:fs';\ntry {\n  const max = readFileSync('/proc/sys/fs/inotify/max_user_watches','utf8').trim();\n  if (Number(max) < 524288) console.warn('inotify max_user_watches low:', max);\n} catch {} // non-Linux","typeGuard":null,"tryCatchPattern":"try {\n  await watcherDriver.start(onChange);\n} catch (err) {\n  if (err instanceof AggregateError && err.message === 'Failed to start watch mode.') {\n    for (const e of err.errors) console.error('watcher root failure:', e);\n  }\n  throw err;\n}","preventionTips":["Ensure all roots exist and are readable before starting watch mode.","On Linux, raise fs.inotify.max_user_watches for large repos.","Narrow roots and set watchPathIgnorePatterns to keep the initial walk under the 240s ready timeout.","Keep watchman healthy (`watchman version`, `watchman shutdown-server` on wedge)."],"tags":["haste-map","watcher","watch-mode","inotify","watchman","timeout"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}