5.7 Cache & Execution

Two identical-looking commands can behave very differently: one finishes without executing anything, while the next rebuilds a long chain of actions. “The cache missed” sounds like an explanation, but it hides the questions that matter. Which kind of state was expected to survive? What lookup identity changed? Which action first diverged between the two invocations?

This section turns that vague complaint into a controlled comparison. The organizing idea is reuse expectation followed by execution evidence: first name the layer that could have reused work, then compare what the invocations actually presented to execution. That order separates a cold analysis graph from an action-cache miss, and separates one changed producer from the downstream actions it caused to run.

First Locate The Reuse Boundary

5.7.1 Cache Internals Reference provides the map. Bazel retains computations, external-repository material, and action results through different mechanisms with different scopes and lifetimes. A server restart, a fresh output base, and a different machine therefore cross different reuse boundaries. They are not interchangeable ways to make a build “cold.”

Read this article first when the symptom is ambiguous: fetching happened again, loading or analysis became slow, outputs disappeared, or a disk or remote cache did not supply an expected result. Its role is to help you name five things before testing a hypothesis: the subject being reused, the layer, its sharing scope, its lookup identity, and the value or bytes that must still exist. The earlier map in 2.4.2 Where Bazel Caches Things tells an operator where cache state lives. This reference adds the distinctions needed to explain why a particular layer did or did not reuse it.

Do not memorize cache directories and treat cleanup as a diagnostic. Clearing state collapses several hypotheses into one destructive experiment and removes the entries you needed to inspect. Preserve the surprising pair of invocations until you can say which boundary the experiment is intended to cross.

Then Find The First Execution Divergence

Once the question is “why did these actions run differently?”, move to 5.7.2 Execution Log Analysis. Capture compact execution logs for two controlled invocations of the same focused command, then compare their recorded spawns. Inputs, arguments, environment, platform properties, outputs, and cache metadata turn “a rebuild happened” into differences you can trace.

The reading direction matters. Start at the earliest meaningful changed producer, not the largest downstream cascade. A generated output that changes can make many consumers run, but those consumers are consequences rather than independent root causes. If recorded inputs agree while an output differs, the logs have exposed a non-hermeticity lead. 2.3.3 Non-Determinism Sources supplies the deeper model for investigating it. The comparison is evidence to test, not an automatic verdict.

The two child articles therefore answer complementary questions:

What reuse did I expect, and across which boundary?
                         |
                         v
What is the first recorded action difference between the invocations?

The first question prevents category errors. The second prevents a visible cascade from being mistaken for its cause.

Read By Symptom, But Keep The Order

For a general “why did this rebuild?” investigation, read both articles in order. Use Cache Internals Reference to state the expected layer and scope, then use Execution Log Analysis to compare a matched pair. Keep the Bazel version, target, configuration, platform, toolchain, relevant environment, and server state attached to that pair.

If the problem is limited to fetching, loading, analysis, cache retention, or the difference between output-tree and AC/CAS reuse, the first article may be enough. If you already know that actions executed and have two comparable invocations, skim the layer taxonomy and go directly to execution logs. Return to the cache reference if the log diff points to cache policy or to a scope that was never actually shared.

After this section, 5.9.1 Skyframe Data Model opens the in-memory evaluator layer in detail. Go there only when the remaining question concerns retained computations or dependency edges. Execution logs remain the better evidence for what participated in execution. Internal graph topology does not replace them.

think

Trace: Two identical-looking invocations execute different work. What must you establish before changing flags or deleting state, and where should the comparison begin?

Reveal

Name the reuse layer, the subject and identity expected to match, the boundary across which reuse was expected, and the single controlled difference between the invocations. Preserve the state, then compare execution evidence from the first meaningful changed producer rather than starting at the largest downstream cascade.

key takeaway

Cache and execution analysis is a two-stage comparison: identify the reuse layer, scope, identity, and stored value you expected to match. Then compare controlled execution logs to find the first action-level divergence. Preserve state, trace from cause toward cascade, and do not use “the cache” as a substitute for naming the mechanism under investigation.