[rush] rush build with build cache enabled will crash when a symlink file links to a directory
Summary
When I run rush build, the error likes:
2025/11/27 10:53:38 Error calculating the state of the repo. (inner error: Error: git --no-optional-locks exited with code 128:
2025/11/27 10:53:38 fatal: Unable to hash <my_symlink_file>
2025/11/27 10:53:38
2025/11/27 10:53:38 at spawnGitAsync (*/common/temp/install-run/@[email protected]/node_modules/@rushstack/package-deps-hash/lib/getRepoState.js:227:15)
2025/11/27 10:53:38 at async hashFilesAsync (*/common/temp/install-run/@[email protected]/node_modules/@rushstack/package-deps-hash/lib/getRepoState.js:266:30)
2025/11/27 10:53:38 at async getDetailedRepoStateAsync (*/common/temp/install-run/@[email protected]/node_modules/@rushstack/package-deps-hash/lib/getRepoState.js:340:36)
2025/11/27 10:53:38 at async Promise.all (index 0)
2025/11/27 10:53:38 at async tryGetSnapshotAsync (*/common/temp/install-run/@[email protected]/node_modules/@microsoft/rush-lib/dist/commons.js:22694:89)
2025/11/27 10:53:38 at async PhasedScriptAction._runInitialPhasesAsync (*/common/temp/install-run/@[email protected]/node_modules/@microsoft/rush-lib/dist/commons.js:21058:33)
2025/11/27 10:53:38 at async PhasedScriptAction.runAsync (*/common/temp/install-run/@[email protected]/node_modules/@microsoft/rush-lib/dist/commons.js:21032:37)
2025/11/27 10:53:38 at async PhasedScriptAction.onExecuteAsync (*/common/temp/install-run/@[email protected]/node_modules/@microsoft/rush-lib/dist/commons.js:19507:16)
2025/11/27 10:53:38 at async PhasedScriptAction._executeAsync (*/common/temp/install-run/@[email protected]/node_modules/@rushstack/ts-command-line/lib/providers/CommandLineAction.js:64:9)
2025/11/27 10:53:38 at async RushCommandLineParser.onExecuteAsync (*/common/temp/install-run/@[email protected]/node_modules/@rushstack/ts-command-line/lib/providers/CommandLineParser.js:262:13)). Continuing without diffing files.
2025/11/27 10:53:38 Analyzing repo state... DONE (1.31 seconds)
2025/11/27 10:53:38
2025/11/27 10:53:38 Selected 15 operations:
2025/11/27 10:53:38 *** (build)
2025/11/27 10:53:38 *** (build2)
2025/11/27 10:53:38 *** (pre-build)
2025/11/27 10:53:38 *** (build)
2025/11/27 10:53:38 *** (build2)
2025/11/27 10:53:38 *** (pre-build)
2025/11/27 10:53:38 *** (build)
2025/11/27 10:53:38
2025/11/27 10:53:38 Executing a maximum of 128 simultaneous processes...
2025/11/27 10:53:38 Error: Build cache is only supported if running in a Git repository. Either disable the build cache or run Rush in a Git repository.
2025/11/27 10:53:38 rush build - Errors! (1.44 seconds)
Repro steps
- Create a symlink to a directory.
- Commit the symlink file into Git.
- Run
rush build
Expected result: Get a better error message or track the real path directory files to calculate cache entry id.
Details
I traced the error code and found the cause of the error as follows:
-
git ls-treelists symlink files. -
git hash-objectappears to treat symlinks to directories as actual directories, causing the error. (I'm not very sure howgit hash-objectworks)
I think there are two possible solutions here:
-
Clearly state the cause of the error, specify that symlinks to directories are not supported, and suggest adding the symlink to
.gitignoreorincrementalBuildIgnoredGlobs. -
Track files within the symlink directory and recursively compute the hash for the realpath files, avoiding circular recursion.
Standard questions
Please answer these questions to help us investigate your issue more quickly:
| Question | Answer |
|---|---|
@microsoft/rush globally installed version? |
5.155.1 |
rushVersion from rush.json? |
5.155.1 |
useWorkspaces from rush.json? |
Yes |
| Operating system? | Mac |
| Would you consider contributing a PR? | Yes |
Node.js version (node -v)? |
22.20.0 |
This is an interesting edge case. A better error message makes sense, or handling it correctly would be better. The file mode is 120000 and git ls-tree returns a hash. @LPegasus, can you provide a minimal repro?
This is an interesting edge case. A better error message makes sense, or handling it correctly would be better. The file mode is
120000andgit ls-treereturns a hash. @LPegasus, can you provide a minimal repro?
Sure. https://github.com/LPegasus/rushstack-issue-5479
Run rush update && rush test to see the error.
With #5500 , Rush will now categorize symlinks separately from files, and will therefore be able to ignore them if they are committed. If there are local changes to them returned by git status there will still be breaks, because git status does not return mode information about affected files.
Hi, @dmichon-msft . Thank you for your fix of the symlink crash!
The scenario where I encountered the issue was not about committing symlinks to the git repository, but rather that during the deployment build process, symlinks are generated. These symlinks are not included in the .gitignore, causing rush build to report an error and exit.
I understand that the fix for #5500 involves excluding symlinks from the hash key calculation process. This may potentially mask some issues related to incorrect build cache hits. Therefore, I was wondering if there could be a feature that forces an error when symlink files are detected?
I am not sure if scenarios where build dependencies leak in some manner are something rush.js needs to detect. For example, another recent case of build dependency leakage involved a project using tsc --build with reference projects, which detached the build project's dependencies graph from rush.js and led to incorrect cache hits. Perhaps this type of issue is difficult to systematically prevent within rush.js.