Failure caching assumes a CompileFailed is a function of
the sources, which is true for source errors. But zinc also surfaces I/O write
failures ("error writing X.class") as compiler problems, so an environmental
failure (a concurrent target/ deletion, a permission blip) was cached under the
same mechanism and replayed from the global action cache on every later build,
even after the cause was gone. When the poisoned task is the metabuild compile
this is self-sustaining and unrecoverable from inside sbt: project loading
fails, so no task -- including clean -- can run, and only deleting the global
cache by hand recovers. The replayed diagnostics also name files/permissions
that no longer exist.
Refs #9455
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
1.0 KiB
Environmental compile failures are no longer cached
sbt caches a CompileFailed so that an unchanged, still-broken compile does not
re-run from scratch (#7662). But zinc also reports I/O write failures ("error
writing X.class") as compiler problems, so a one-off environmental failure (a
concurrent target/ deletion, a permission blip) was cached under the same
mechanism and replayed on every later build, even after the cause was gone. When
it hit the metabuild compile the build stayed wedged across restarts, recoverable
only by deleting the global cache by hand. Compile failures whose errors carry no
source position are now treated as environmental and left uncached, so the next
build retries for real. A position-less failure already sitting in a cache
written by an earlier sbt is likewise no longer replayed: the task re-runs and a
success overwrites the stale entry, so previously wedged builds recover on
upgrade without deleting the cache.
This addresses #9455.