Skip to content

[9.3.0] Fix hang on include() cycles in MODULE.bazel (https://github.com/bazelbuild/bazel/pull/30737) - #30804

Merged
iancha1992 merged 1 commit into
bazelbuild:release-9.3.0from
bazel-io:cp30737-9.3.0-061034
Aug 21, 2026
Merged

[9.3.0] Fix hang on include() cycles in MODULE.bazel (https://github.com/bazelbuild/bazel/pull/30737)#30804
iancha1992 merged 1 commit into
bazelbuild:release-9.3.0from
bazel-io:cp30737-9.3.0-061034

Conversation

@bazel-io

Copy link
Copy Markdown
Member

Description

ModuleFileFunction#advanceHorizon compiles the module files named by the current horizon of include() statements and returns their own include() statements as the next horizon, without ever checking whether a file has already been compiled. A cycle among included files thus keeps the horizon non-empty forever, so that ModuleFileFunction spins in an endless loop, re-reading and re-compiling the same files until the build is interrupted. For the same reason, a "diamond" include structure results in a number of compilations that is exponential in the include depth.

This PR skips include labels that have already been compiled (or that appear more than once in the same horizon) when advancing the horizon, which makes the loop terminate, and reports actual cycles as an error when the module file is executed, where the chain of include() calls is readily available:

ERROR: .../MODULE.bazel:1:8: include() cycle detected: //java:java.MODULE.bazel -> //python:python.MODULE.bazel -> //java:java.MODULE.bazel

Note that skipping already-compiled files does not change evaluation semantics: include() behaves as if the included file were textually inserted at the location of the call, and a file reachable via multiple include() paths is still executed once per path. Only the compilation of the file is shared.

Motivation

A single typo in a MODULE.bazel file (e.g. a foo.MODULE.bazel that includes itself) currently makes Bazel spin at 100% CPU with no output and no way to make progress. include() is only allowed in the root module and in modules with a non-registry override, so this is reachable from user-authored files.

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: Cycles between MODULE.bazel files connected via include() are now reported as an error instead of hanging the build.

Closes #30737.

PiperOrigin-RevId: 967604241
Change-Id: I8c0d8d082338e41c6b83712d452c82ad6da8517a

Commit ce039a7

### Description

`ModuleFileFunction#advanceHorizon` compiles the module files named by the current horizon of `include()` statements and returns their own `include()` statements as the next horizon, without ever checking whether a file has already been compiled. A cycle among included files thus keeps the horizon non-empty forever, so that `ModuleFileFunction` spins in an endless loop, re-reading and re-compiling the same files until the build is interrupted. For the same reason, a "diamond" include structure results in a number of compilations that is exponential in the include depth.

This PR skips include labels that have already been compiled (or that appear more than once in the same horizon) when advancing the horizon, which makes the loop terminate, and reports actual cycles as an error when the module file is executed, where the chain of `include()` calls is readily available:

```
ERROR: .../MODULE.bazel:1:8: include() cycle detected: //java:java.MODULE.bazel -> //python:python.MODULE.bazel -> //java:java.MODULE.bazel
```

Note that skipping already-compiled files does not change evaluation semantics: `include()` behaves as if the included file were textually inserted at the location of the call, and a file reachable via multiple `include()` paths is still executed once per path. Only the compilation of the file is shared.

### Motivation

A single typo in a `MODULE.bazel` file (e.g. a `foo.MODULE.bazel` that includes itself) currently makes Bazel spin at 100% CPU with no output and no way to make progress. `include()` is only allowed in the root module and in modules with a non-registry override, so this is reachable from user-authored files.

### Build API Changes

No

### Checklist

- [x] I have added tests for the new use cases (if any).
- [ ] I have updated the documentation (if applicable).

### Release Notes

RELNOTES: Cycles between `MODULE.bazel` files connected via `include()` are now reported as an error instead of hanging the build.

Closes bazelbuild#30737.

PiperOrigin-RevId: 967604241
Change-Id: I8c0d8d082338e41c6b83712d452c82ad6da8517a
@bazel-io bazel-io added team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file. area-Bzlmod Bzlmod-specific PRs, issues, and feature requests awaiting-review PR is awaiting review from an assigned reviewer labels Aug 20, 2026
@bazel-io
bazel-io requested a review from a team as a code owner August 20, 2026 06:11
@bazel-io bazel-io added team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file. area-Bzlmod Bzlmod-specific PRs, issues, and feature requests awaiting-review PR is awaiting review from an assigned reviewer labels Aug 20, 2026
@bazel-io
bazel-io requested a review from Wyverald August 20, 2026 06:11
@Wyverald
Wyverald added this pull request to the merge queue Aug 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Aug 20, 2026
@iancha1992
iancha1992 added this pull request to the merge queue Aug 21, 2026
Merged via the queue into bazelbuild:release-9.3.0 with commit 9067c32 Aug 21, 2026
42 checks passed
@github-actions github-actions Bot removed the awaiting-review PR is awaiting review from an assigned reviewer label Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Bzlmod Bzlmod-specific PRs, issues, and feature requests team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants