Skip to content

Make BazelBuildSystem error message complete on opaque exits#158

Merged
obj-p merged 1 commit intomainfrom
fix/bazel-build-diagnostic-completeness
May 2, 2026
Merged

Make BazelBuildSystem error message complete on opaque exits#158
obj-p merged 1 commit intomainfrom
fix/bazel-build-diagnostic-completeness

Conversation

@obj-p
Copy link
Copy Markdown
Owner

@obj-p obj-p commented May 2, 2026

Summary

CI run 25243519727 surfaced a snapshotBazel failure where bazel exited 7 with both stderr and stdout empty. The pre-existing error formatter in runBazel:

stderr: output.stderr.isEmpty ? output.stdout : output.stderr,

discarded one stream by design and yielded an empty diagnostic when both were empty. The test failure looked like:

Project build failed (exit code 7):

— with nothing after the colon, leaving no way to tell whether the failure was a corrupt bazel binary, a concurrent workspace lock, an analysis failure with output redirected, or something else.

The rerun of the same SHA passed, so this particular instance was transient. But silent-flake conditions in Bazel (server crashes, remote-cache evictions mid-fetch, partial bazelisk downloads, fd exhaustion) are common enough that we'll see it again. When we do, the test failure should point at the offending command, not at the absence of one.

Change

The thrown BuildSystemError.buildFailed now carries:

  • the bazel command and arguments that failed
  • the working directory (projectRoot)
  • the captured stderr (or (empty) if truly silent)
  • the captured stdout (or (empty) if truly silent)

No behavior change on the happy path. No public-API change to BuildSystemError.buildFailed — the diagnostic is composed into the existing stderr: field.

Why not also try to fix the underlying flake?

Without an actual reproduction we'd be speculating (version mismatch? concurrent jobs? remote cache state?). The diagnostic improvement is the load-bearing fix: the next occurrence will be self-describing instead of opaque, and we can address the actual root cause then. Adding speculative defensive layers (retry-on-fail, isolated --output_user_root) without evidence risks masking legitimate build failures.

Test plan

  • swift build clean
  • swift test --filter SnapshotCommandTests/snapshotBazel passes (4.8s) — happy path unaffected
  • CI green

CI run 25243519727 surfaced a snapshotBazel failure where bazel exited
7 with both stderr and stdout empty. The pre-existing error formatter
in `runBazel` — `output.stderr.isEmpty ? output.stdout : output.stderr`
— discarded one stream by design and yielded an empty diagnostic when
both were empty: the test failure message was just "Project build
failed (exit code 7):" with nothing after the colon, leaving no way
to determine whether the failure was a corrupt bazel binary, a
concurrent workspace lock, an analysis failure with output redirected,
or something else.

The rerun of the same SHA passed, so the failure was transient — but
silent-flake conditions in Bazel are common enough (server crashes,
remote cache evictions mid-fetch, partial bazelisk downloads, file
descriptor exhaustion) that we will encounter this again. When we do,
we want the test failure to point at the offending command rather
than just at the absence of one.

The new diagnostic carries:
  - the bazel command and arguments that failed
  - the working directory (projectRoot)
  - the captured stderr (or `(empty)` if truly silent)
  - the captured stdout (or `(empty)` if truly silent)

No behavior change on the happy path; no public-API change to
`BuildSystemError.buildFailed`. Verified locally:
`swift test --filter SnapshotCommandTests/snapshotBazel` passes in 4.8s.
@obj-p obj-p merged commit 2137f96 into main May 2, 2026
4 checks passed
@obj-p obj-p deleted the fix/bazel-build-diagnostic-completeness branch May 2, 2026 13:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant