Skip to content

core: NpmConfig.load ignores dir/.npmrc when an ancestor has package.json/node_modules (common on Windows) #44062

Closed

Description

@BigBrown10

Summary

NpmConfig.load(dir) (packages/core/src/npm-config.ts) can silently ignore the .npmrc in the requested directory on machines where an ancestor directory contains a package.json or node_modules folder. On Windows this is common: the user profile root (C:\Users\<name>) frequently ends up with both from an accidental install, and opencode's own package cache lives under %LOCALAPPDATA%, inside that profile.

What happens

  1. @npmcli/config finds the project prefix by walking up from cwd until it sees a directory containing package.json or node_modules.
  2. For opencode's plugin/package cache dirs (empty on first install), the walk exits the cache and stops at the polluted ancestor.
  3. The requested directory's .npmrc is never read; the ancestor's (or none) is used instead. When the walk stops at the home directory, its .npmrc also collides with the user config and gets dropped entirely ((same as "user" config, ignored)).
  4. NpmConfig.load maps any internal failure to {}, so installs proceed against the default registry with no diagnostic.

Observed on a real machine: probe with cwd = %TEMP%\npmcfg-X containing registry=https://registry.example.test/:

localPrefix: C:\Users\edogu          <- home, not cwd
flat.registry: https://registry.npmjs.org/
sources: ... (same as "user" config, ignored)=project ...

The five existing tests in packages/core/test/npm-config.test.ts fail on this machine and pass in CI only because /tmp ancestors are clean there — i.e. CI cannot see this bug class.

Impact

Plugin/skill dependency installs configured through a project or cache-adjacent .npmrc (private registries, mirrors) silently hit the default registry on affected Windows setups.

Proposed direction

Pin the synthetic CLI prefix to the requested directory (argv: [..., "--prefix=" + dir]). loadLocalPrefix() short-circuits on a cli prefix, making "read dir/.npmrc as project config" deterministic regardless of ancestors. This matches what callers already assume (Npm.install passes path: dir to Arborist explicitly).

Activity

  1. neriousy commented on Oct 19, 2026

    @neriousy
    Member

    In v2, npm configuration loading explicitly pins the project prefix to the requested directory, so an ancestor's package.json or node_modules no longer redirects the local .npmrc lookup. This is present in v2.0.0. To get v2: npm i -g @opencode/cli@latest or curl -fsSL https://opencode.ai/v2/install | bash (desktop: update the app). If you still see this on v2, please open a new issue with the details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions