5.5.3 Remote Cache Diagnostics

recommended

A remote-cache percentage is useful only after you define what was eligible to hit the cache. A clean CI build after a broad source change, a repeated build of the same revision, and a developer's incremental build exercise different action sets. Mixing them into one number can hide a regression or manufacture one.

The same discipline applies to correctness incidents. A cache miss means Bazel did not reuse an entry. It is not evidence that an entry was poisoned. Start by classifying the observation, then collect the narrowest data that can distinguish changed action identity, disabled caching, and an incorrect reused result.

Classify a remote-cache symptom by the first decisive evidence
A miss and a wrong reused result begin different investigations. Neither should be inferred from hit rate alone.
SYMPTOM
Unexpected miss, low hit rate, or wrong output
Preserve the invocation. Do not clear the cache.
then
1 · COHORT COMPARISON
Are the invocations comparable?
Same workflow, revision, platform, Bazel version, configuration, and cold/repeated/incremental class.
no
MONITORING CLASSIFICATION
Low hit rate is not yet a cache defect
Segment the cohort and compare action counts against its own baseline.
if yes
2 · EXECUTION-LOG DIFF
Does the first affected action differ?
Compare command, environment, input digests, outputs, and platform.
yes
ORDINARY MISS
Changed action identity
Trace why the first differing value entered the action.
if no
3 · CACHEABILITY
Is the action cacheable, with cache reads accepted?
Check the record, target tags, and canonical effective command line.
no
NO REUSE EXPECTED
Non-cacheable or read-disabled
Fix policy or configuration before investigating stored bytes.
if yes, rebuild twice without reuse
4 · UNCACHED DETERMINISM
Do independent matched builds agree byte-for-byte?
Compare the earliest divergent output and trace its producer.
no
PRODUCER DEFECT
Non-hermetic or non-deterministic action
The producer changes output without a corresponding recorded-input change.
if yes
5 · REUSED-RESULT COMPARISON
Does the preserved reused result match both stable uncached outputs?
Require the same action identity before comparing bytes.
REUSED RESULT AGREES
No poisoning evidence
Continue with the preserved invocation and earliest unexplained divergence.
REUSED RESULT DIFFERS
Genuine wrong reused-result evidence
Same action identity and stable uncached outputs, but a conflicting cached result. Preserve writer provenance.
Classify the first decisive divergence as identity or policy, producer determinism, or a wrong result actually reused for the same identity.

Turn hit rate into a comparable signal

Track cache behavior by a stable cohort: repository and branch class, command or workflow, platform, Bazel version, relevant configuration, and whether the run is cold, repeated, or incremental. Record action counts as well as ratios. Ten misses among twenty eligible actions and ten misses among twenty thousand need different responses.

Do not adopt a universal “healthy” percentage. The mapped sources describe cache-hit trends and drill-downs, but they do not establish an 80% threshold. Set a baseline from comparable successful invocations, then alert on a sustained change from that baseline. Segment by mnemonic or target when an aggregate stays flat: one expensive action class can lose all of its hits while a large volume of cheap hits keeps the overall ratio reassuring.1

Bazel's final process summary is a quick invocation-level check. It labels results reused from the remote cache as remote cache hit. Local cache hits are not included in that summary. Treat it as triage, not as a complete historical metric.2 A BES-backed dashboard can retain invocation trends, while request- level telemetry can answer which action transferred an artifact and when the first cascade of executions began.3 5.5.1 Build Event Protocol (BEP) introduces the event stream, and 5.5.2 Metrics & Monitoring develops the monitoring pipeline.

Diagnose misses from the first divergence

Use a controlled pair of invocations. First repeat the same target, revision, flags, and platform. Only after reuse works on one machine should you compare CI with a developer host or two worker pools. This separates a basic cache or configuration problem from cross-environment action-key drift.2

For unexpected rebuilding, --explain=<path> with --verbose_explanations provides a quick, high-level account of why Bazel considered work out of date. It is a lead, not proof of why a remote lookup missed. The decisive comparison is between execution logs from the two builds:

bazel build //app:release \
  --execution_log_compact_file=/tmp/exec-a.log

bazel build //app:release \
  --execution_log_compact_file=/tmp/exec-b.log

An execution-log record includes the action's command line, environment, inputs, outputs, execution strategy, and cache behavior. Bazel's compact format is recommended because it is much smaller and has little runtime overhead. The portable operation is to capture comparable Bazel logs, align the relevant action records, and compare their declared identity inputs and cache observations. Bazel's source-tree execution-log parser can produce an aligned textual comparison. As a version-checked convenience case, bb explain can automate a structural comparison and trace an early changed action through its transitive effects.2,4 Neither tool invocation proves that the first reported divergence is the ultimate cause; it supplies a lead to verify.

Interpret the first meaningful divergence before looking at the rebuild cascade:

ObservationWorking diagnosisNext check
Command, environment, input digest, or platform differsThe action identity changed. This is an ordinary missFind why the configuration or host value entered the action
Actions match but a record is not cacheableThe rule or target disabled cachingInspect the mnemonic and target label. Check for a no-cache tag
Actions match and are cacheable, but no lookup is acceptedEffective flags disabled cache readsInspect the canonical command line in BEP for remote_accept_cached
An output changes while recorded inputs do notThe producing action is non-hermeticRebuild independently, compare the output bytes, and inspect the first divergent file

One documented cross-machine investigation found HOME inherited into a test environment. The different values changed the action between CI and the developer host. Replacing the inherited value with the constant the test actually required restored sharing.1 Other common causes include timestamps embedded in archives and absolute host paths in generated metadata.5 These are action or output determinism defects, not cache-server corruption.

If actions appear identical and cacheable, inspect the effective configuration before blaming storage. A BEP text file contains a structured_command_line message labeled canonical. It shows options after rc-file expansion. In particular, --noremote_accept_cached disables accepting cached results.2 5.7.2 Execution Log Analysis covers deeper log comparison and tooling.

Require stronger evidence for cache poisoning

Use cache poisoning narrowly: a lookup for a particular action identity reuses an output that is wrong for that action. Low hit rate cannot establish this—a poisoned entry must be hit to have an effect. Nor does a changed output with a changed action key establish it. That is a different cache entry.

When wrong output appears only with cache reads enabled, preserve the failing invocation, the reused action, and the suspect action-result and blob identities. Then run independent builds with remote reads and writes disabled under matched inputs and compare their outputs in isolated local state. Two uncached builds that disagree point first to non-determinism. Stable independent outputs that agree with each other but disagree with the reused result are much stronger evidence that the cached action result is bad. Compare the earliest divergent artifact with a binary-aware tool such as Diffoscope, and trace it to its producer rather than deleting the whole cache and losing the evidence.4

Use an exact matched-build test to make that claim reproducible:

  1. Pin the same revision, target, Bazel version, platform, toolchains, environment, and non-cache flags. Record the digest of the wrong artifact from a read-enabled build and retain its BEP and compact execution log.
  2. Create two new, empty output bases. Do not clean or delete the original output base or any shared cache. In each new output base, repeat the build with remote cache reads and writes disabled and with --disk_cache=, then capture the same evidence. Use the supported flags for the pinned Bazel version and confirm from the canonical command line and backend observations that the diagnostic builds neither read from nor wrote to the suspect cache.
  3. Confirm in the canonical command line and execution logs that the same producer action was compared. Hash its output from all three builds. If the two bypass outputs match each other while the read-enabled build records a cache hit for the same action identity and yields different bytes, the test is evidence of wrong reuse. If the bypass outputs differ, investigate non-determinism instead.

The controls have separate jobs. Disabling remote reads prevents reuse, while disabling remote writes prevents the diagnostic rebuilds from overwriting or adding evidence in the suspect shared cache. --disk_cache= disables a configured disk cache for these runs.

A fresh --output_base prevents the local action cache and existing output tree from satisfying the action. The repository cache stores downloaded external artifacts, not action results, so disabling or deleting it does not strengthen this test. Keep remote execution and every other execution setting matched so the test changes cache reuse rather than the execution environment. Stable disagreement establishes only that the cached result is not equivalent to the controlled rebuild for the observed action identity. It does not alone distinguish a compromised writer, an underdeclared input, unsafe key normalization, a producer-version defect, or a backend defect. Continue with 6.2.4 Wrong Cache Result Diagnostics when the investigation must attribute a bad shared result to infrastructure or a writer trust domain.

A non-hermetic producer can populate a shared cache with semantically bad bytes even when the cache service stored exactly what it received. That makes provenance important: record which invocation and trust domain wrote the suspect result. 6.2.4 Wrong Cache Result Diagnostics develops containment policy, such as restricting which builds may write to a shared cache, and infrastructure controls for untrusted writers. Here, the key decision is whether the evidence points to action-key drift, a non-cacheable or read-disabled configuration, a non-deterministic producer, or a wrong result actually reused for the same action identity.

key takeaway

Monitor remote-cache hit rate only within comparable cohorts and against an empirical baseline. There is no source-backed universal 80% healthy threshold. Use the process summary for quick triage, historical observability for trends, and paired compact execution logs to locate the first differing action input, environment value, command, or platform.

Do not label misses or changing keys as cache poisoning. First prove that the same action identity reused a wrong result, compare it with independent cache-bypassing builds, and distinguish a bad cached result from a non-deterministic producer. Preserve that evidence before containment or eviction.

Check your understanding · 4 questions

1.A dashboard shows that the remote-cache hit rate fell sharply this week. What is the best first interpretation?

Select one answer

2.Match each observation to the strongest working diagnosis:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
The paired execution logs differ in command, environment, input digest, or platform
The action identities match, but the record is not cacheable
Two matched, cache-bypassing builds produce different bytes
Matched uncached builds agree, but a reused result for that identity differs

3.Which observations are sufficient reasons to investigate configuration or action identity before suspecting cache poisoning?

Select all that apply

4.Classify the evidence from a wrong-output investigation.

Choose True or False for each sentence

A poisoned cache entry must be hit before it can affect an output.
Different outputs under different action keys prove that one cache entry is poisoned.
Two uncached builds that disagree point first to producer non-determinism.
Deleting the entire cache is the best way to preserve evidence about the suspect writer.
0 of 4 answered

Footnotes

  1. Bazel Build Data: Avoiding Pitfalls in Debugging and Optimizing Builds — cohort drill-down, BEP versus execution-log scope, and a cache miss caused by an inherited HOME 1 2

  2. Debugging Remote Cache Hits for Remote Execution — process-summary semantics, same-machine and cross-machine workflow, cacheability checks, canonical command line, and execution-log comparison 1 2 3 4

  3. Bazel Remote Cache Debugging — request-level sorting, artifact-transfer inspection, and finding the earliest action in a rebuild cascade

  4. bb explain: Understanding Why Bazel Rebuilds — compact-log comparison, earliest-divergence analysis, non-hermetic output detection, and Diffoscope workflow 1 2

  5. How Airbnb supports Bazel at scale — independent determinism checks and examples of timestamps and absolute paths in outputs