jestjs/jest · error · ValidationError
haste.enableSymlinks is incompatible with watchman
Error message
haste.enableSymlinks is incompatible with watchman
What it means
normalize() (normalize.ts:1061-1067) rejects the combination of watchman-based file watching with haste.enableSymlinks. Watchman does not follow symlinks reliably, so following symlinks in the haste map while using watchman produces inconsistent module resolution. The ValidationError tells the user to pick one: disable symlinks or stop using watchman.
Solutions
- Set haste.enableSymlinks to false (the default) if you need watchman.
- Disable watchman: run jest --no-watchman or set watchman: false in config, if you need symlink following.
- Switch to a non-watchman crawler (e.g. configure haste accordingly) when symlink support is required.
Example fix
// before
module.exports = {
watchman: true,
haste: { enableSymlinks: true },
};
// after (option A: keep watchman)
module.exports = {
watchman: true,
haste: { enableSymlinks: false },
};
// after (option B: keep symlinks)
module.exports = {
watchman: false,
haste: { enableSymlinks: true },
}; Defensive patterns
Strategy: validation
Validate before calling
function validateHasteWatchman(cfg: { watchman?: boolean; haste?: { enableSymlinks?: boolean } }): void {
if (cfg.watchman && cfg.haste?.enableSymlinks) {
throw new Error('haste.enableSymlinks is incompatible with watchman; pick one');
}
} Prevention
- Default haste.enableSymlinks to false unless you specifically need symlink following.
- If you need symlinks (pnpm-style), disable watchman (watchman: false).
- Add a config-validation step in CI to catch incompatible option pairs.
When it happens
Trigger: Setting { watchman: true, haste: { enableSymlinks: true } } in jest.config; enabling enableSymlinks while watchman is the default crawler on the platform; CI that forces watchman=true alongside symlink support.
Common situations: Monorepos using symlinks (pnpm, yarn workspaces with links) where a user tried to enable symlink support without disabling watchman; copying a config snippet that set haste.enableSymlinks; defaulting watchman on macOS/Linux dev machines.
Related errors
- jest-haste-map: enableSymlinks config option was set, but…
- seed value must be between `-0x80000000` and `0x7fffffff`…
- Cannot find module
- Cannot merge config in form of callback
- Could not resolve a module for a custom reporter. Module…
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/85c7eec12f791c4d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/jest-config/src/normalize.ts:1062
return {
config: watchPlugin[1] || {},
path: resolveWatchPlugin(newOptions.resolver, {
filePath: watchPlugin[0],
requireResolveFunction: requireResolve,
rootDir: options.rootDir,
}),
};
}
});
break;
}
// @ts-expect-error: automock is missing in GlobalConfig, so what
newOptions[key] = value;
return newOptions;
}, newOptions);
if (options.watchman && options.haste?.enableSymlinks) {
throw new ValidationError(
'Validation Error',
'haste.enableSymlinks is incompatible with watchman',
'Either set haste.enableSymlinks to false or do not use watchman',
);
}
for (const [i, root] of newOptions.roots.entries()) {
verifyDirectoryExists(root, `roots[${i}]`);
}
try {
// try to resolve windows short paths, ignoring errors (permission errors, mostly)
newOptions.cwd = tryRealpath(process.cwd());
} catch {
// ignored
}
newOptions.testSequencer = resolveSequencer(newOptions.resolver, {View on GitHub (pinned to 8e6d128e4a)