{"id":"85c7eec12f791c4d","repo":"jestjs/jest","slug":"haste-enablesymlinks-is-incompatible-with-watchman","errorCode":null,"errorMessage":"haste.enableSymlinks is incompatible with watchman","messagePattern":"haste\\.enableSymlinks is incompatible with watchman","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/jest-config/src/normalize.ts","lineNumber":1061,"sourceCode":"            return {\n              config: watchPlugin[1] || {},\n              path: resolveWatchPlugin(newOptions.resolver, {\n                filePath: watchPlugin[0],\n                requireResolveFunction: requireResolve,\n                rootDir: options.rootDir,\n              }),\n            };\n          }\n        });\n        break;\n    }\n    // @ts-expect-error: automock is missing in GlobalConfig, so what\n    newOptions[key] = value;\n    return newOptions;\n  }, newOptions);\n\n  if (options.watchman && options.haste?.enableSymlinks) {\n    throw new ValidationError(\n      'Validation Error',\n      'haste.enableSymlinks is incompatible with watchman',\n      'Either set haste.enableSymlinks to false or do not use watchman',\n    );\n  }\n\n  for (const [i, root] of newOptions.roots.entries()) {\n    verifyDirectoryExists(root, `roots[${i}]`);\n  }\n\n  try {\n    // try to resolve windows short paths, ignoring errors (permission errors, mostly)\n    newOptions.cwd = tryRealpath(process.cwd());\n  } catch {\n    // ignored\n  }\n\n  newOptions.testSequencer = resolveSequencer(newOptions.resolver, {","sourceCodeStart":1043,"sourceCodeEnd":1079,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-config/src/normalize.ts#L1043-L1079","documentation":"Near the end of normalize (packages/jest-config/src/normalize.ts:1060), Jest validates that `haste.enableSymlinks` is not combined with `watchman: true`. Watchman's file crawling does not follow symlinks the way Jest's haste-map symlink support expects, so enabling both produces incorrect module resolution; Jest throws a ValidationError.","triggerScenarios":"Configuring `{ watchman: true, haste: { enableSymlinks: true } }` (watchman is on by default, so merely adding `haste.enableSymlinks: true` is enough to trigger it unless watchman is explicitly disabled).","commonSituations":"Enabling symlink support for a monorepo that uses symlinks/yarn workspaces/pnpm, while leaving the default watchman crawler enabled.","solutions":["Disable watchman: set `watchman: false` (Jest will fall back to its own crawler which supports symlinks).","Or disable symlink support: set `haste: { enableSymlinks: false }` if you do not actually need symlink following."],"exampleFix":"// before\nmodule.exports = {\n  watchman: true, // default\n  haste: { enableSymlinks: true },\n};\n\n// after (option A: keep symlinks, drop watchman)\nmodule.exports = {\n  watchman: false,\n  haste: { enableSymlinks: true },\n};","handlingStrategy":"validation","validationCode":"function validateHasteWatchman(cfg: { watchman?: boolean; haste?: { enableSymlinks?: boolean } }): void {\n  if (cfg.watchman !== false && cfg.haste?.enableSymlinks) {\n    throw new Error('haste.enableSymlinks requires watchman:false');\n  }\n}","typeGuard":"const symlinksEnabled = (cfg: any) => Boolean(cfg?.haste?.enableSymlinks);\nconst watchmanEnabled = (cfg: any) => cfg?.watchman !== false;","tryCatchPattern":null,"preventionTips":["If you need symlink support, set `watchman: false`.","Default watchman is on; explicitly disable it when enabling haste.enableSymlinks.","Document the trade-off: Jest's crawler is slower than watchman."],"tags":["jest-config","haste","watchman","symlinks","validation"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}