Skip to content

Name the compilation cache when a damaged object fails the build - #139

Merged
janicduplessis merged 3 commits into
mainfrom
@janic/cas-recovery
Aug 31, 2026
Merged

Name the compilation cache when a damaged object fails the build#139
janicduplessis merged 3 commits into
mainfrom
@janic/cas-recovery

Conversation

@janicduplessis

@janicduplessis janicduplessis commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Closes #138.

Description

A damaged compilation cache fails the build with an error that points at the wrong thing:

error: failed to scan dependencies for source '.../Pods/sqlite3/sqlite-src-3500400/sqlite3.c' (in target 'sqlite3')
error: failed to scan dependencies for source '.../Pods/nanopb/pb_encode.c' (in target 'nanopb')

The pods are innocent. The transcript carries the line that identifies the cause, which Stim does not surface:

error: CAS-based dependency scan failed: not a IncludeTreeRoot node kind (in target 'sqlite3')
error: Could not build module '_DarwinFoundation1'

The modules it cannot build are SDK modules, which is what marks the cache rather than the project. The targets it names change from run to run, because they are whichever ones reach the damaged object first, so the failure reads as a pod incompatibility and survives a CLI upgrade.

Solution

remedyFor matches the CAS scan line, so the build names the cache and the command that empties it.

gc --delete --all empties every shared cache, which costs the build cache and the Metro caches to recover one damaged cache. gc --cache <name> selects the caches whose name or directory carries <name>, and reports and empties only those. A name no cache carries reports the caches the machine holds instead of printing "Nothing to reclaim".

A scoped run inspects no device, project entry or lock, so it says so rather than reporting a clean machine it never looked at. It also skips the EAS session sweep, which otherwise shells out to eas-cli and takes the EAS project lock to produce a result the scoped report discards.

The failure is documented in the errors guide topic, since a user who reads pod names in the error looks there before reading a flag list.

The selector is deliberately a substring over name and directory, not a fixed list of cache ids: discoverCaches mixes registered and detected caches whose names come from the manifest, so a fixed list would go stale.

Risk

--cache narrows what gc acts on and defaults to today's behavior when absent, so the destructive path only ever gets smaller. A blank value is rejected: an empty string fell through to a full machine-wide run and a whitespace string selected every cache, so both widened what --delete --all reaches.

The match is the not a IncludeTreeRoot node kind line alone. A CAS scan can fail for other reasons, and telling those users to empty a cache and pay a cold build would be wrong.

Test plan

Reproduced on a real Expo app (tlon-apps, RN 0.86.3, Xcode 26.5):

  • fresh pod install, then build with a damaged cache: fails, exit 65, targets vary per run
  • empty the compilation cache, rebuild the same tree: succeeds in 201s
  • gc --all --cache "compilation cache" reports only the two compilation caches, leaving the build cache, Gradle and Metro maps untouched, and reports no devices or projects
  • gc --cache nope reports the four caches the machine holds
  • gc --all --cache "compilation cache" states which state it did not inspect
  • gc --cache "" and gc --cache " " are rejected instead of widening the run

Xcode fails the dependency scan when a compilation cache object has the
wrong node kind, and reports it per source file. The targets it names are
whichever ones reach the damaged object first, so the failure reads as a
pod incompatibility. The line that identifies the cache,
`CAS-based dependency scan failed: not a IncludeTreeRoot node kind`, stays
in the transcript.

Match that line in `remedyFor` so the build names the cache and the command
that empties it.

`gc --delete --all` empties every shared cache, which costs the build cache
and the Metro caches to recover from a damaged compilation cache. Add
`gc --cache <name>`: it acts on the caches whose name or directory carries
<name>, and leaves every other cache, device and project entry untouched.
A name that no cache carries reports the caches the machine holds.

Closes #138
A cache-scoped run inspects no device, project entry or lock, so the report
must not claim the machine is clean. Carry the scope in the report and say
what the run did not inspect.

Reject a blank `--cache` value. An empty string fell through to a full
machine-wide run, and a whitespace string selected every cache, so both
widened what `--delete --all` reaches.

Skip the EAS session sweep for a cache-scoped run. It shells out to eas-cli
and takes the EAS project lock to produce a result the report discards.

Narrow the compilation cache match to the node-kind line. Other CAS scan
failures have other causes, and the remedy is wrong for them.

Document the failure in the `errors` guide topic, which is where a user who
reads pod names in the error looks, and cover the new flag in the guide
contract test and the field test protocol.
The remedy reaches the user through a diagnostic list capped at
MAX_DIAGNOSTICS, so it survives only while the scan failure leads the
transcript. A real failing transcript puts it first, ahead of the module
failures it causes. Pin that with a test that caps a long transcript.

Cover the blank `--cache` rejection, which had no test.
@janicduplessis
janicduplessis marked this pull request as ready for review August 31, 2026 18:23
@janicduplessis
janicduplessis merged commit 1fbde68 into main Aug 31, 2026
5 checks passed
@janicduplessis
janicduplessis deleted the @janic/cas-recovery branch August 31, 2026 18:24
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.

A damaged compilation cache fails the build with an error that names innocent pods

1 participant