What makes a task relocatable, and how can wrong input normalization cause false cache hits or chronic misses across machines?
answer
- relocatable = key independent of abs path
- @PathSensitive(RELATIVE) default ABSOLUTE
- under-normalized -> chronic cross-machine miss
- under-declared -> false hit (correctness bug)
- reproducible archives: no timestamps, sorted order
basics
~20 sA relocatable task produces the same key regardless of the project's absolute path. Wrong path-sensitivity puts absolute paths in the key, causing misses on other machines; missing/undeclared inputs cause false hits where stale outputs are wrongly restored.
solid answer
~50 s**Relocatability** means a task's cache key is independent of where the project lives on disk, so an entry produced in `/home/ci/checkout` can be reused at `/Users/dev/repo`. It's achieved by declaring input files with `@PathSensitive(RELATIVE)` (or `NAME_ONLY`/`NONE`) and outputs that don't bake absolute paths. If you forget normalization, the absolute path is hashed into the key, so every machine with a different checkout path gets a **chronic miss** — caching appears 'on' but never hits cross-machine. The opposite failure is the **false hit**: a task depends on something it didn't declare (an env var, a sibling file, the JDK minor version), so two genuinely different scenarios compute the *same* key. Gradle restores stale outputs that are wrong for the current context. False hits are worse than misses — they're silent correctness bugs. Diagnose both with `-Dorg.gradle.caching.debug=true`: chronic misses show diverging path hashes; false hits show a *missing* component you'd expect to differ. Fix with correct normalization, complete input declaration, and reproducible outputs.
code
kotlin · 9 lines@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE) // <- makes the task relocatable
abstract val templates: ConfigurableFileCollection
// reproducible outputs so downstream tasks cache reliably
tasks.withType<Jar>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}go deeper
Know that absolute paths can sneak into the key and that all real inputs must be declared.
Explain @PathSensitive options and how under-normalization causes cross-machine misses.
Contrast chronic misses vs false hits, identify undeclared inputs, and enforce reproducible outputs.
Define org-wide normalization/reproducibility standards and review processes so cache correctness isn't left to chance per task.
## Relocatability: the key must not encode the checkout path The build cache only pays off when an entry computed in one location is reusable in another — your laptop, a teammate's, a fresh CI agent. A task is **relocatable** when its cache key does not depend on the absolute filesystem path of the project. Gradle achieves this through **input normalization**: - `@PathSensitive(PathSensitivity.RELATIVE)` — the key reflects each input file's *relative* path within its root plus content. Most source-consuming tasks want this. - `@PathSensitive(NAME_ONLY)` — only file name + content matters. - `@PathSensitive(NONE)` — only content; paths ignored entirely (e.g. a bundle of resources where location is irrelevant). - `@Classpath` / `@CompileClasspath` — order-insensitive, jar-internal-timestamp-insensitive classpath hashing. If you declare an `@InputFiles` without path sensitivity, Gradle uses ABSOLUTE by default — the machine-specific path enters the key, and **no two checkouts agree**, so the cross-machine hit rate is ~0 even though caching is enabled. ## The two failure modes ### Chronic miss (under-normalized) Absolute paths or jar timestamps leak into the key. Symptoms: local builds may hit, but CI and teammates always execute. Debug log shows the input file hash differing only because the path prefix differs. ### False hit (under-declared) The task's real output depends on an input it never declared: a `System.getenv("PROFILE")`, a generated file read directly, or non-ABI bytecode differences. Two different contexts hash to the *same* key, and Gradle restores the wrong outputs. This is a **correctness** bug, not a performance one — a build can pass with stale artifacts. There is no automatic detection; you find it by reasoning about whether *every* thing the task reads is a declared input, optionally validated by Gradle's runtime API for tracking and by `--scan` input audits. ## Making outputs reproducible too Even with correct inputs, *non-reproducible outputs* (jars with embedded timestamps, file order) undermine downstream tasks' caching. Set: ```kotlin tasks.withType<AbstractArchiveTask>().configureEach { isPreserveFileTimestamps = false isReproducibleFileOrder = true } ``` ## Diagnosis recap - Chronic cross-machine miss -> check path sensitivity; look for absolute paths in the debug key trail. - Suspicious correctness after a hit -> hunt for undeclared inputs; the debug trail will be *missing* a component that should distinguish the two cases. Relocatability + complete declaration + reproducible outputs are the three pillars that make cache keys both *stable* (hit often) and *correct* (never falsely).
- Why is a false cache hit more dangerous than a cache miss?A miss only costs time — the task re-runs correctly. A false hit silently restores wrong outputs, so the build is fast but incorrect, and it can ship broken artifacts.
- Caching is enabled but CI never hits while local re-builds do. What do you check first?Path sensitivity. The absolute checkout path almost certainly leaks into the key (ABSOLUTE default), so the differing CI path makes every key unique. Apply @PathSensitive(RELATIVE).
- How do non-reproducible jars hurt caching even with correct inputs?Their content hash differs run-to-run, so tasks consuming them as @InputFiles/@Classpath get different keys, cascading misses downstream. Disable timestamps and fix file order.
Relocatability is like a recipe written with 'top shelf' instead of 'GPS coordinates of my pantry' — anyone can follow it. An undeclared input is a secret ingredient the recipe forgets to list, so two cooks get the same recipe but different dishes.
saying these in an interview costs you the question
- Treating a false hit as harmless because the build is green
- Assuming caching is reusable cross-machine without any path normalization
- Ignoring reproducibility of produced jars