Skip to content

Fix Could not chdir in tw.exe for long runfiles paths on Windows - #30610

Closed
rdesgroppes wants to merge 1 commit into
bazelbuild:masterfrom
rdesgroppes:windows-tw-chdir-long-path
Closed

Fix Could not chdir in tw.exe for long runfiles paths on Windows#30610
rdesgroppes wants to merge 1 commit into
bazelbuild:masterfrom
rdesgroppes:windows-tw-chdir-long-path

Conversation

@rdesgroppes

@rdesgroppes rdesgroppes commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

On Windows, bazel test fails for tests run through the native test wrapper (tw.exe) whose runfiles directory path exceeds MAX_PATH (260 characters), with ERROR_FILENAME_EXCED_RANGE (206) from ChdirToRunfiles's call to SetCurrentDirectoryW.

The \\?\ extended-length prefix used by #29921 for CreateProcessW's lpApplicationName would not help here: SetCurrentDirectoryW ignores that prefix regardless of length, as stated by MicrosoftDocs/feedback#1441.
=> declare longPathAware in tw.exe's manifest (tw_manifest.xml, embedded via tw_resources.rc and windows_resources in tools/test/BUILD), which Windows 10 1607+ honors for SetCurrentDirectoryW once paired with the LongPathsEnabled registry opt-in.

Once ChdirToRunfiles succeeds into a long directory, StartSubprocess's CreateProcessW call also needs its current directory passed explicitly: implicit inheritance (lpCurrentDirectory=nullptr) otherwise fails with ERROR_INVALID_PARAMETER once cwd exceeds MAX_PATH, even from a longPathAware process.
=> populate it so that windows::WaitableProcess::Create can shorten it internally (through AsShortPath), like it does for the executable's own path.

The new testLongRunfilesPathChdir in test_wrapper_test.py exercises both fixes: the cwd fix always fails in StartSubprocess when missing, while a missing manifest can surface as either ChdirToRunfiles's error or rules_cc's Runfiles::Create (FindTestBinary) failing first, depending on path length.

Motivation

Fixes #30609

Build API Changes

No

Checklist

  • I have added tests for the new use cases (if any).
  • I have updated the documentation (if applicable).

Release Notes

RELNOTES: Fix Could not chdir in tw.exe for long runfiles paths on Windows.

@rdesgroppes
rdesgroppes force-pushed the windows-tw-chdir-long-path branch 3 times, most recently from 9f38717 to 2386018 Compare August 6, 2026 12:21
@rdesgroppes
rdesgroppes marked this pull request as ready for review August 6, 2026 12:26
@github-actions github-actions Bot added the awaiting-review PR is awaiting review from an assigned reviewer label Aug 6, 2026
Comment thread src/test/py/bazel/test_wrapper_test.py Outdated
# Long enough that both the runfiles chdir target and the executable's
# own path exceed MAX_PATH, exercising ChdirToRunfiles's longPathAware
# manifest and StartSubprocess's explicit-cwd fix.
long_name = 'x' * 150

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
long_name = 'x' * 150
long_name = 'x' * 256

would make it more obvious that this is long enough.

@rdesgroppes rdesgroppes Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried 'x' * 256 first, but it breaks the build for an unrelated reason: bisecting, 233 still passes but 234 fails with ERROR_INVALID_NAME, because Bazel writes a <name>.exe.runfiles_manifest file for each test target.
It turns out individual path components are capped at 255 characters, per Naming and referencing shares, directories, files, and metadata and What are file path length limits?.
At 234, <name>.exe.runfiles_manifest is 234 + 22 = 256 characters, one over the limit (233 lands exactly on the 255 boundary).
In short, that's a different limit than the MAX_PATH one this test targets.

=> landed on splitting the length across both the package directory and the target name instead (_130_chars, to make the length self-explanatory in the spirit of your suggestion), so the overall runfiles path still exceeds MAX_PATH while each individual path component stays comfortably under the 255-char ceiling.

@fmeum
fmeum requested a review from meteorcloudy August 6, 2026 16:42
@fmeum

fmeum commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

@bazel-io fork 9.3.0

@github-actions github-actions Bot added the community-reviewed Reviewed by a trusted community contributor label Aug 6, 2026
On Windows, `bazel test` fails for tests run through the native test
wrapper (`tw.exe`) whose runfiles directory path exceeds `MAX_PATH`
(260 characters), with `ERROR_FILENAME_EXCED_RANGE` (206) from
`ChdirToRunfiles`'s call to `SetCurrentDirectoryW`.

The `\\?\` extended-length prefix used by bazelbuild#29921 for `CreateProcessW`'s
`lpApplicationName` would not help here: `SetCurrentDirectoryW` ignores
that prefix regardless of length, as stated by
MicrosoftDocs/feedback#1441.
=> declare `longPathAware` in `tw.exe`'s manifest (`tw_manifest.xml`,
embedded via `tw_resources.rc` and `windows_resources` in
`tools/test/BUILD`), which Windows 10 1607+ honors for
`SetCurrentDirectoryW` once paired with the `LongPathsEnabled`
registry opt-in.

Once `ChdirToRunfiles` succeeds into a long directory,
`StartSubprocess`'s `CreateProcessW` call also needs its current
directory passed explicitly: implicit inheritance
(`lpCurrentDirectory=nullptr`) otherwise fails with
`ERROR_INVALID_PARAMETER` once `cwd` exceeds `MAX_PATH`, _even from a
`longPathAware` process_.
=> populate it so that `windows::WaitableProcess::Create` can shorten it
internally (through `AsShortPath`), like it does for the executable's
own path.

The new `testChdirToRunfilesWithPathLongerThanMaxPath` in
`test_wrapper_test.py` exercises both fixes: the cwd fix always
fails in `StartSubprocess` when missing, while a missing manifest
can surface as either `ChdirToRunfiles`'s error or `rules_cc`'s
`Runfiles::Create` (`FindTestBinary`) failing first, depending on
path length.
@rdesgroppes
rdesgroppes force-pushed the windows-tw-chdir-long-path branch from 2386018 to 4859368 Compare August 7, 2026 08:51

@meteorcloudy meteorcloudy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@meteorcloudy meteorcloudy added awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally and removed awaiting-review PR is awaiting review from an assigned reviewer labels Aug 7, 2026
@github-actions github-actions Bot removed the awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally label Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-reviewed Reviewed by a trusted community contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bazel test fails on Windows with error 206 when the runfiles path exceeds MAX_PATH

3 participants