Skip to content

[8.6.0] Compensate for Windows filesystems lacking junction support#28367

Merged
iancha1992 merged 1 commit intobazelbuild:release-8.6.0from
bazel-io:cp27598-8.6.0
Jan 23, 2026
Merged

[8.6.0] Compensate for Windows filesystems lacking junction support#28367
iancha1992 merged 1 commit intobazelbuild:release-8.6.0from
bazel-io:cp27598-8.6.0

Conversation

@bazel-io
Copy link
Member

Problem:
Bazel fails completely on Windows when using filesystems that don't support junction/reparse point operations (e.g., virtiofs, VirtualBox shared folders, network drives, RAM disks).

The fatal error occurs when ReadSymlinkOrJunction fails during path resolution (e.g., when Starlark code calls .realpath): "Cannot read link: DeviceIoControl: Incorrect function".
This causes build analysis to abort completely.

Additionally, CreateJunction failures when creating convenience symlinks produce cryptic error messages, though these were already non-fatal warnings.

Both fail because DeviceIoControl returns ERROR_INVALID_FUNCTION when the filesystem doesn't implement FSCTL_GET_REPARSE_POINT or FSCTL_SET_REPARSE_POINT operations.

Proposed solution:
Handle ERROR_INVALID_FUNCTION gracefully by treating it as a "not supported" condition rather than a fatal error:

  1. in ReadSymlinkOrJunction (file.cc:592): return kNotALink instead of kError when ERROR_INVALID_FUNCTION occurs. This allows path resolution to continue for non-symlink paths on unsupported filesystems.
  2. in CreateJunction (file.cc:461): return new kNotSupported result code when ERROR_INVALID_FUNCTION occurs. This produces clear "filesystem does not support junctions" warnings instead of cryptic "Incorrect function" messages. This improves UX but doesn't change behavior (these failures were already non-fatal).

This follows the try-first, fallback-on-error pattern (EAFP) used by other major projects when handling unsupported filesystem operations.

Prior art:

Impact:

  • enables Bazel to work on virtiofs, VirtualBox shared folders, RAM disks, and other filesystems that don't support Windows junction operations.
  • convenience symlinks (bazel-bin, bazel-out, etc.) still won't be created, but now with clearer error messages.

Limitations:
Full junction support would require filesystem-level changes (e.g., virtiofs driver improvements).

Testing:
Tested on Windows 11 VM with host directory mounted via virtiofs, with rules_pkg. Before change: build analysis aborted with "Cannot read link" fatal error. After change: builds complete successfully with clearer warnings about unsupported junctions for convenience symlinks.

Closes #27598.

PiperOrigin-RevId: 833360316
Change-Id: I3751602b2bd793c1cee75b7b66fa73c955a72517

Commit dab96fc

**Problem**:
Bazel fails completely on Windows when using filesystems that don't support junction/reparse point operations (e.g., virtiofs, VirtualBox shared folders, network drives, RAM disks).

The fatal error occurs when `ReadSymlinkOrJunction` fails during path resolution (e.g., when Starlark code calls `.realpath`): "Cannot read link: DeviceIoControl: Incorrect function".
This causes build analysis to abort completely.

Additionally, `CreateJunction` failures when creating convenience symlinks produce cryptic error messages, though these were already non-fatal warnings.

Both fail because `DeviceIoControl` returns `ERROR_INVALID_FUNCTION` when the filesystem doesn't implement `FSCTL_GET_REPARSE_POINT` or `FSCTL_SET_REPARSE_POINT` operations.

**Proposed solution:**
Handle `ERROR_INVALID_FUNCTION` gracefully by treating it as a "not supported" condition rather than a fatal error:
1. in `ReadSymlinkOrJunction` (`file.cc`:592): return `kNotALink` instead of `kError` when `ERROR_INVALID_FUNCTION` occurs. This allows path resolution to continue for non-symlink paths on unsupported filesystems.
2. in `CreateJunction` (`file.cc`:461): return new `kNotSupported` result code when `ERROR_INVALID_FUNCTION` occurs. This produces clear "filesystem does not support junctions" warnings instead of cryptic "Incorrect function" messages. This improves UX but doesn't change behavior (these failures were already non-fatal).

This follows the try-first, fallback-on-error pattern (EAFP) used by other major projects when handling unsupported filesystem operations.

**Prior art:**
- Rust (rust-lang/rust#138133): checks `ERROR_INVALID_FUNCTION`, `ERROR_NOT_SUPPORTED`, and `ERROR_INVALID_PARAMETER` for filesystem operation fallbacks in `std::fs::rename`.
- Microsoft STL (microsoft/STL#2077): handles junctions and reparse point errors including `ERROR_INVALID_PARAMETER` with robust fallback logic in `filesystem.cpp`.
- Go (golang/go#20506): uses fallback strategies when symlink APIs are unavailable on different Windows versions.
- WinFsp (winfsp/winfsp#88): documents that `ERROR_INVALID_FUNCTION` indicates `STATUS_NOT_IMPLEMENTED` for unsupported operations.
- Microsoft Learn: recommends checking `FILE_SUPPORTS_REPARSE_POINTS` flag via `GetVolumeInformation`, but try-catch approach is simpler and handles edge cases where detection succeeds but operations fail.

**Impact**:
- enables Bazel to work on virtiofs, VirtualBox shared folders, RAM disks, and other filesystems that don't support Windows junction operations.
- convenience symlinks (bazel-bin, bazel-out, etc.) still won't be created, but now with clearer error messages.

**Limitations**:
Full junction support would require filesystem-level changes (e.g., virtiofs driver improvements).

**Testing:**
Tested on Windows 11 VM with host directory mounted via virtiofs, with [rules_pkg](https://github.com/bazelbuild/rules_pkg/blob/6cdaba69ee76463b2b8e97e8d243dbb6115c3aee/toolchains/git/git_configure.bzl#L40). Before change: build analysis aborted with "Cannot read link" fatal error. After change: builds complete successfully with clearer warnings about unsupported junctions for convenience symlinks.

Closes bazelbuild#27598.

PiperOrigin-RevId: 833360316
Change-Id: I3751602b2bd793c1cee75b7b66fa73c955a72517
@bazel-io bazel-io requested a review from a team as a code owner January 21, 2026 18:02
@bazel-io bazel-io added the awaiting-review PR is awaiting review from an assigned reviewer label Jan 21, 2026
@bazel-io bazel-io requested a review from tjgq January 21, 2026 18:02
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request addresses a fatal error in Bazel on Windows when using filesystems that lack junction support, such as virtiofs. The changes gracefully handle ERROR_INVALID_FUNCTION from DeviceIoControl calls. In ReadSymlinkOrJunction, this error is now treated as if the path is not a link, preventing build analysis from aborting. In CreateJunction, it provides a clearer warning message. The changes are well-contained, logical, and consistent across the native C++ and Java layers. The approach is sound and aligns with practices in other major projects. I find no issues with the implementation.

@iancha1992 iancha1992 enabled auto-merge January 21, 2026 18:04
@iancha1992 iancha1992 added the team-Remote-Exec Issues and PRs for the Execution (Remote) team label Jan 21, 2026
@iancha1992 iancha1992 added this pull request to the merge queue Jan 23, 2026
github-merge-queue bot pushed a commit that referenced this pull request Jan 23, 2026
…28367)

**Problem**:
Bazel fails completely on Windows when using filesystems that don't
support junction/reparse point operations (e.g., virtiofs, VirtualBox
shared folders, network drives, RAM disks).

The fatal error occurs when `ReadSymlinkOrJunction` fails during path
resolution (e.g., when Starlark code calls `.realpath`): "Cannot read
link: DeviceIoControl: Incorrect function".
This causes build analysis to abort completely.

Additionally, `CreateJunction` failures when creating convenience
symlinks produce cryptic error messages, though these were already
non-fatal warnings.

Both fail because `DeviceIoControl` returns `ERROR_INVALID_FUNCTION`
when the filesystem doesn't implement `FSCTL_GET_REPARSE_POINT` or
`FSCTL_SET_REPARSE_POINT` operations.

**Proposed solution:**
Handle `ERROR_INVALID_FUNCTION` gracefully by treating it as a "not
supported" condition rather than a fatal error:
1. in `ReadSymlinkOrJunction` (`file.cc`:592): return `kNotALink`
instead of `kError` when `ERROR_INVALID_FUNCTION` occurs. This allows
path resolution to continue for non-symlink paths on unsupported
filesystems.
2. in `CreateJunction` (`file.cc`:461): return new `kNotSupported`
result code when `ERROR_INVALID_FUNCTION` occurs. This produces clear
"filesystem does not support junctions" warnings instead of cryptic
"Incorrect function" messages. This improves UX but doesn't change
behavior (these failures were already non-fatal).

This follows the try-first, fallback-on-error pattern (EAFP) used by
other major projects when handling unsupported filesystem operations.

**Prior art:**
- Rust (rust-lang/rust#138133): checks `ERROR_INVALID_FUNCTION`,
`ERROR_NOT_SUPPORTED`, and `ERROR_INVALID_PARAMETER` for filesystem
operation fallbacks in `std::fs::rename`.
- Microsoft STL (microsoft/STL#2077): handles junctions and reparse
point errors including `ERROR_INVALID_PARAMETER` with robust fallback
logic in `filesystem.cpp`.
- Go (golang/go#20506): uses fallback strategies when symlink APIs are
unavailable on different Windows versions.
- WinFsp (winfsp/winfsp#88): documents that `ERROR_INVALID_FUNCTION`
indicates `STATUS_NOT_IMPLEMENTED` for unsupported operations.
- Microsoft Learn: recommends checking `FILE_SUPPORTS_REPARSE_POINTS`
flag via `GetVolumeInformation`, but try-catch approach is simpler and
handles edge cases where detection succeeds but operations fail.

**Impact**:
- enables Bazel to work on virtiofs, VirtualBox shared folders, RAM
disks, and other filesystems that don't support Windows junction
operations.
- convenience symlinks (bazel-bin, bazel-out, etc.) still won't be
created, but now with clearer error messages.

**Limitations**:
Full junction support would require filesystem-level changes (e.g.,
virtiofs driver improvements).

**Testing:**
Tested on Windows 11 VM with host directory mounted via virtiofs, with
[rules_pkg](https://github.com/bazelbuild/rules_pkg/blob/6cdaba69ee76463b2b8e97e8d243dbb6115c3aee/toolchains/git/git_configure.bzl#L40).
Before change: build analysis aborted with "Cannot read link" fatal
error. After change: builds complete successfully with clearer warnings
about unsupported junctions for convenience symlinks.

Closes #27598.

PiperOrigin-RevId: 833360316
Change-Id: I3751602b2bd793c1cee75b7b66fa73c955a72517

Commit
dab96fc

Co-authored-by: Rgis Desgroppes <[email protected]>
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 23, 2026
@iancha1992 iancha1992 added this pull request to the merge queue Jan 23, 2026
Merged via the queue into bazelbuild:release-8.6.0 with commit d32dd14 Jan 23, 2026
47 checks passed
@github-actions github-actions bot removed the awaiting-review PR is awaiting review from an assigned reviewer label Jan 23, 2026
rdesgroppes added a commit to DataDog/datadog-agent that referenced this pull request Feb 27, 2026
### What does this PR do?
Bump `.bazelversion` from 8.5.1 to 8.6.0.

### Motivation
Selected changes between 8.5.1 and 8.6.0:
- Fix visibility for implicit deps of parent rules (bazelbuild/bazel#28722)
- Force rctx.{download_and,}extract to create user-readable files (bazelbuild/bazel#28551)
- Fix disk cache failures on concurrent read-write access on Windows (bazelbuild/bazel#28529)
- Add a target_type argument to ctx.actions.symlink (bazelbuild/bazel#28538)
- Compensate for Windows filesystems lacking junction support (bazelbuild/bazel#28367)
  (our fix)
- Add short_uncached and detailed_uncached options to --test_summary (bazelbuild/bazel#28343)
- Add --experimental_strict_repo_env option (bazelbuild/bazel#28189)
- Make overlaid files executable in http_archive (bazelbuild/bazel#28277)
- Add bazel mod show_repo --all_repos and --all_visible_repos (bazelbuild/bazel#28012)
- Enable --experimental_retain_test_configuration_across_testonly (bazelbuild/bazel#28115)
- Add option to continue with local execution if remote cache is unavailable (bazelbuild/bazel#28001)
rdesgroppes added a commit to DataDog/datadog-agent that referenced this pull request Feb 27, 2026
### What does this PR do?
Bump `.bazelversion` from 8.5.1 to 8.6.0.

### Motivation
Selected changes between 8.5.1 and 8.6.0:
- Fix visibility for implicit deps of parent rules (bazelbuild/bazel#28722)
- Force rctx.{download_and,}extract to create user-readable files (bazelbuild/bazel#28551)
- Fix disk cache failures on concurrent read-write access on Windows (bazelbuild/bazel#28529)
- Add a target_type argument to ctx.actions.symlink (bazelbuild/bazel#28538)
- Compensate for Windows filesystems lacking junction support (bazelbuild/bazel#28367)
  (our fix)
- Add short_uncached and detailed_uncached options to --test_summary (bazelbuild/bazel#28343)
- Add --experimental_strict_repo_env option (bazelbuild/bazel#28189)
- Make overlaid files executable in http_archive (bazelbuild/bazel#28277)
- Add bazel mod show_repo --all_repos and --all_visible_repos (bazelbuild/bazel#28012)
- Enable --experimental_retain_test_configuration_across_testonly (bazelbuild/bazel#28115)
- Add option to continue with local execution if remote cache is unavailable (bazelbuild/bazel#28001)
gh-worker-dd-mergequeue-cf854d bot pushed a commit to DataDog/datadog-agent that referenced this pull request Feb 27, 2026
### What does this PR do?
Bump `bazel` version from 8.5.1 to 8.6.0 to benefit from a series of improvements and fixes.
Ours (bazelbuild/bazel#28367) allows to re-enable "convenience symlinks" for Windows users and makes [`path.realpath`](https://bazel.build/rules/lib/builtins/path#realpath) succeed when sharing a folder between a Linux host and a Windows VM.

### Motivation
Selected changes between 8.5.1 and 8.6.0:
- 💡 bazelbuild/bazel#28001
- bazelbuild/bazel#28012
- 💡 bazelbuild/bazel#28189
- bazelbuild/bazel#28277
- bazelbuild/bazel#28343
- 🐕 bazelbuild/bazel#28367
- bazelbuild/bazel#28529
- bazelbuild/bazel#28538
- bazelbuild/bazel#28551
- bazelbuild/bazel#28722

Co-authored-by: regis.desgroppes <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team-Remote-Exec Issues and PRs for the Execution (Remote) team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants