{"record":{"id":"4c46dc92206155c0","repo":"jestjs/jest","slug":"crawler-retry-failed-original-error-retryerr","errorCode":null,"errorMessage":"Crawler retry failed:\n  Original error: ${retryError.message}\n  Retry error: ${error.message}\n","messagePattern":"Crawler retry failed:\n  Original error: (.+?)\n  Retry error: (.+?)\n","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-haste-map/src/crawlers/index.ts","lineNumber":30,"sourceCode":"export async function crawl(\n  crawlerOptions: CrawlerOptions,\n  useWatchman: boolean,\n  console: Console,\n): ReturnType<typeof nodeCrawl> {\n  const crawlFn = useWatchman ? watchmanCrawl : nodeCrawl;\n\n  const retry = (retryError: Error) => {\n    if (crawlFn === watchmanCrawl) {\n      console.warn(\n        'jest-haste-map: Watchman crawl failed. Retrying once with node ' +\n          'crawler.\\n' +\n          \"  Usually this happens when watchman isn't running. Create an \" +\n          \"empty `.watchmanconfig` file in your project's root folder or \" +\n          'initialize a git or hg repository in your project.\\n' +\n          `  ${retryError}`,\n      );\n      return nodeCrawl(crawlerOptions).catch(error => {\n        throw new Error(\n          'Crawler retry failed:\\n' +\n            `  Original error: ${retryError.message}\\n` +\n            `  Retry error: ${error.message}\\n`,\n        );\n      });\n    }\n\n    throw retryError;\n  };\n\n  try {\n    return await crawlFn(crawlerOptions);\n  } catch (error: any) {\n    return retry(error);\n  }\n}\n","sourceCodeStart":12,"sourceCodeEnd":47,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-haste-map/src/crawlers/index.ts#L12-L47","documentation":"jest-haste-map's file-system crawler first tries watchman; if that fails it retries once with the node (fdir/find) crawler. This error is the terminal failure: BOTH the watchman crawl and the fallback node crawl raised exceptions. The combined message shows the original watchman error and the retry node-crawler error so you can diagnose both. It means the entire haste-map build aborts — no module map is produced.","triggerScenarios":"crawl() catches the watchmanCrawl error, enters the retry path (crawlFn === watchmanCrawl), calls nodeCrawl(crawlerOptions), and nodeCrawl also rejects — e.g. due to EACCES/ENOENT on a root directory, a corrupt filesystem entry, or an unreadable file during the fdir walk. Any exception from nodeCrawl is caught and re-thrown as this combined Error.","commonSituations":"Watchman is installed but misconfigured or its socket is stale, AND a root directory the project points at does not exist or has restrictive permissions (CI containers, Docker mounts, monorepo path typos). Also seen after a branch switch leaves dangling paths referenced by the Jest config roots, or when a symlink loop exists and forceNodeFilesystemAPI is off.","solutions":["Run `watchman version` and `watchman shutdown-server` to reset a stale watchman daemon, then rebuild.","Verify every path in Jest's `roots` / `moduleDirectories` / `testPathIgnorePatterns` resolves and is readable: `ls -la <root>` for each root.","If watchman is the culprit, set `haste: { forceNodeFilesystemAPI: true }` or pass `useWatchman: false` to skip watchman entirely.","Check the two nested messages (Original error / Retry error) for ENOENT/EACCES codes and fix the named path's permissions or remove it from roots."],"exampleFix":"// before\nmodule.exports = {\n  roots: ['<rootDir>/src', '<rootDir>/packages/legacy'],\n};\n// after — legacy path no longer exists; removed it\nmodule.exports = {\n  roots: ['<rootDir>/src'],\n};","handlingStrategy":"validation","validationCode":"// Before building, verify every root exists and is readable.\nimport { accessSync, constants } from 'node:fs';\nfunction validateRoots(roots: string[]): void {\n  for (const root of roots) {\n    try {\n      accessSync(root, constants.R_OK);\n    } catch {\n      throw new Error(`jest-haste-map root is not readable: ${root}`);\n    }\n  }\n}\n// Call before HasteMap.create(...)\nvalidateRoots(config.roots);","typeGuard":"function areRootsAccessible(roots: string[]): boolean {\n  return roots.every(root => {\n    try { accessSync(root, constants.R_OK); return true; }\n    catch { return false; }\n  });\n}","tryCatchPattern":"try {\n  await hasteMap.build();\n} catch (error) {\n  if (error.message.startsWith('Crawler retry failed')) {\n    // Inspect error.message for both Original and Retry errors,\n    // then either fix paths or disable watchman.\n    console.error('Crawl failed for both backends. Root cause:\\n', error.message);\n  }\n  throw error;\n}","preventionTips":["Keep watchman healthy: run `watchman version` in CI before Jest.","Validate all configured roots exist at startup (accessSync).","Prefer `useWatchman: false` in CI where the node crawler is more predictable.","Avoid pointing roots at directories that branches may delete."],"tags":["watchman","filesystem","crawler","configuration","permissions"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}