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

  1. Set haste.enableSymlinks to false (the default) if you need watchman.
  2. Disable watchman: run jest --no-watchman or set watchman: false in config, if you need symlink following.
  3. 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

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


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)