2.3 Hermeticity & Sandboxing
bazel build //app:server --spawn_strategy=local may work while the same target
fails in a sandbox. It may also pass on one laptop, fail on CI, and look fixed
after bazel clean. These outcomes call for the same investigation: what did
the action really depend on, and did Bazel record it?
Trustworthy reuse needs two properties. The action's recorded inputs must match its real inputs, and equivalent executions must produce stable output bytes. Sandboxing can expose violations of the first property on the local machine. Non-determinism is the separate failure of the second.
Compare The Recorded And Real Inputs
2.3.1 Hermeticity defines input hermeticity. Source files are only part of the action's world. Tools, configuration, environment, and repository setup can also change what it does. A hidden input can create a false cache hit, so the risk is correctness rather than only lost speed.
2.3.2 Sandboxing turns that principle into execution-time evidence. Bazel runs an action in a prepared world containing the inputs it staged, not everything available on the host. When an undeclared header, tool, or file is missing from that staged view, a host-dependent action fails.
Sandboxing often turns that incomplete description into a useful failure. If
switching to local makes the failure disappear, the comparison is evidence of
host coupling, not usually a permanent fix. The
genrule-sandbox-paths bad_relative_path target
demonstrates the mistake: it hard-codes config/input.txt without declaring the
file in srcs, so sandboxed execution reports
cat: config/input.txt: No such file or directory while local execution happens
to find the host path.
This declared-input discipline prepares actions for the strategy choices in 2.5.1 Strategies Abstraction. Switching strategies is safe only when the action does not depend on the accidental contents of one execution environment.
Separate Missing Inputs From Unstable Outputs
2.3.3 Non-Determinism Sources covers a sandbox's main limit. A tool can receive the right declared inputs and still write the current date, embed an absolute output-base path, serialize data in random order, or consult other unstable state. The sandbox completed its job, but the output bytes can still drift.
If an action is failing now, 2.3.4 First-Response Debugging Flags gives the shortest
escalation path. --verbose_failures shows the failed command,
--sandbox_debug preserves the sandbox for inspection, and --subcommands
shows the wider execution stream. If the build succeeds but clean executions
produce different artifacts or keep destabilizing reuse, investigate
non-determinism before blaming the cache.
A local-only success is evidence, not a durable .bazelrc repair. Persistent
strategy and environment choices belong to 2.5.2 Strategies & Mnemonics and
3.2.6 Hermeticity Settings, but the immediate goal is to model the missing
input or tool.
Try the hermeticity-settings snippet to compare an undeclared host environment value with an explicitly pinned --action_env. The consuming genrule is intentionally small enough to inspect completely.
Hermeticity makes reuse trustworthy: the declared action must contain its real inputs, and those inputs must produce stable outputs. Sandboxing exposes missing declarations. Determinism checks the behavior that remains once the declared world is complete.
Sections in this chapter · 4
Hermetic actions depend only on declared inputs, tools, and configuration so cache reuse is trustworthy.
How local sandboxes stage declared inputs, expose hidden dependencies, and approximate remote execution conditions.
Sources of non-deterministic output bytes that declared inputs and sandboxing alone cannot prevent.
Choosing --verbose_failures, --sandbox_debug, or --subcommands for first-response action diagnostics.