Skip to content

Pass COURSIER_CACHE to coursier when fetching unpinned repositories#1601

Open
vadikmironov wants to merge 1 commit into
bazel-contrib:masterfrom
vadikmironov:coursier-cache-home-env
Open

Pass COURSIER_CACHE to coursier when fetching unpinned repositories#1601
vadikmironov wants to merge 1 commit into
bazel-contrib:masterfrom
vadikmironov:coursier-cache-home-env

Conversation

@vadikmironov

Copy link
Copy Markdown
Contributor

Coursier derives its default cache location from the JVM's user.home, which on Linux comes from the passwd database and ignores $HOME, while these rules derive the shared cache location from $HOME (or $XDG_CACHE_HOME). When the two disagree — e.g. $HOME remapped to a network-mounted home directory — coursier bypasses the shared cache during a repin, re-downloads artifacts into the passwd home, and the fetch then fails with:

Error while trying to parse the path of file in the coursier cache: /home/<user>/.cache/coursier/v1/...

Repro: on Linux, run REPIN=1 bazel run @unpinned_maven//:pin with HOME pointing anywhere other than the passwd home dir (env HOME=/some/other/dir ... bazel run @unpinned_maven//:pin). Before this change the repin hard-fails as above; after it, coursier uses (and populates) the $HOME-derived shared cache.

Fix: always pass the Starlark-computed cache location to the spawned coursier process via the COURSIER_CACHE environment variable, as the pinned flow already does. The logic is extracted into get_coursier_environment (public for testing). If none of the variables a shared cache location can be derived from is set (HOME/XDG_CACHE_HOME/COURSIER_CACHE), the environment is left untouched so coursier keeps using its own default.

Behavior note: a -Dcoursier.cache=... passed via COURSIER_OPTS is now overridden by the forced environment variable in the unpinned flow; that configuration previously failed the relativization step anyway.

A follow-up PR will fix the same user.home vs $HOME skew in the Java resolver tooling (.netrc lookup, local .m2/.gradle caches).

🤖 Generated with Claude Code

Coursier derives its default cache location from the JVM's `user.home`,
which on Linux comes from the passwd database and ignores $HOME, while
these rules derive the shared cache location from $HOME. When the two
disagree (e.g. $HOME remapped to a network mount), repinning bypasses
the shared cache and fails with "Error while trying to parse the path
of file in the coursier cache".

Pass the computed location to the spawned coursier process via
COURSIER_CACHE, as the pinned flow already does. If no variable a cache
location can be derived from is set, leave the environment untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@shs96c

shs96c commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Why not just set the COURSIER_CACHE env var in this? That's the kind of problem it's designed to fix....

If that's not the right answer, why not make this branch unconditional?

@vadikmironov

Copy link
Copy Markdown
Contributor Author

Thanks a lot for the feedback!

Setting COURSIER_CACHE manually does work, and this PR keeps it working (an existing value is read first and passed through). For the setup with mounted home and redefined HOME env var the first experience of setting up rules_jvm_external is a bit rough though - one runs bazel run @unpinned_maven//:pin and gets back a cryptic stack trace saying "Error while trying to parse the path of file in the coursier cache". Discovering that the fix is to set COURSIER_CACHE requires digging through the rules_jvm_external source and finding the user.home vs $HOME mismatch. The rule already knows where it expects the cache to be and this change just tells the spawned coursier process the same thing.

Making that branch unconditional would pass the repo-local directory for unpinned repos too (defeating the shared cache they are supposed to use). If you meant something like --cache get_coursier_cache_or_default(ctx, _is_unpinned(ctx)) then this is an option and it would be equivalent to this change. I opted for the env var because --cache is coursier's highest-precedence setting - users can still pass their own --cache via additional_coursier_options and it wins over the env var. Forcing --cache ourselves would compete with the user setting, but more importantly the coursier invocation would fail for the unpinned case as coursier rejects a duplicated --cache option ("Argument --cache: argument ??? already specified").

@vadikmironov

Copy link
Copy Markdown
Contributor Author

@shs96c , please do let me know if the explanation make sense? Just to re-iterate - this PR is using COURSIER_CACHE env var approach also honoring user input when provided. As mentioned, --cache option doesn't look to be working as clean.

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.

2 participants