Skip to content

[bug] teamai packages install crashes in pnpm projects (npm install run in pnpm node_modules tree) #1102

Closed

Description

@bladestone01

Description

teamai packages install (local / non‑global declarations) always fails in a project that uses pnpm, because the npm adapter shells out to npm install with cwd set to the project root. npm's arborist then tries to read the project's pnpm node_modules layout and crashes:

npm error Cannot read properties of null (reading 'matches')

Root cause chain (npm 11.16.0):

TypeError: Cannot read properties of null (reading 'matches')
    at Link.matches (…/npm/node_modules/@npmcli/arborist/lib/node.js:1183:41)
    at Link.canDedupe (…/lib/node.js:1127:15)
    at PlaceDep.pruneDedupable (…/lib/place-dep.js:426:14)
    at new PlaceDep (…/lib/place-dep.js:278:14)

npm install cannot understand node_modules/.pnpm/** (the symlink farm pnpm creates), so arborist walks a Link whose target is null and dereferences it.

Two problems for a pnpm project:

  1. teamai never detects the package manager. grep -c pnpm over teamai-cli@0.27.0/dist/index.js → 0. The npm adapter hardcodes:
    this.execute("npm", ["install", …(global ? ["--global"] : []), …specs, …(registry ? ["--registry", registry] : [])], { cwd: context.cwd })
    There is no packageManager field read, no pnpm/yarn/bun detection, no override knob.
  2. Local installs run npm inside the project directory, i.e. exactly the pnpm tree that breaks arborist. (Global installs — --global — do not crash, since they don't parse the project's node_modules.)

Expected: in a pnpm project, teamai packages install should install through pnpm (pnpm add / pnpm add -g), or at minimum not crash and print an actionable message. Issue #325 ("TeamAI 不重造任何包管理器") reserved architecture slots for other ecosystems; pnpm is a package-manager flavor of the npm ecosystem and is currently unsupported.

Reproduction

Minimal, no teamai config needed — the crash is reproducible with a bare npm command in any pnpm project:

# 1. pnpm project with an installed pnpm store
pnpm install

# 2. npm install in that same directory → crash (even --dry-run)
npm install --dry-run lodash
#   npm error Cannot read properties of null (reading 'matches')

Then through teamai (project scope, packages.npm declared or a fresh target):

teamai packages install typescript
#   npm error Cannot read properties of null (reading 'matches')
#   Error: npm install failed (exit 1): npm error Cannot read properties of null …
#     at NpmAdapter.install (…/teamai-cli/dist/index.js:36059:19)
#     at async pkgInstall (…/dist/index.js:36516:7)

Control test proving it is the pnpm layout, not the network or the package:

mkdir /tmp/npmtest && cp package.json /tmp/npmtest/ && cd /tmp/npmtest
npm install --dry-run lodash      # succeeds — no node_modules/.pnpm here
rm -rf /tmp/npmtest

Global path also proves the split:

teamai packages install @playwright/cli --global   # works (no project node_modules walked)

Expected vs actual

  • Expected: teamai packages install <pkg> in a pnpm project resolves the dependency graph with pnpm (respecting pnpm-lock.yaml), or exits cleanly with a "pnpm not supported" message.
  • Actual: an opaque arborist TypeError surfaced as npm install failed (exit 1), with no hint that the real cause is npm-vs-pnpm layout.

Environment

  • OS: Ubuntu 26.04.1 LTS (x64)
  • Node.js: v24.18.0
  • npm: 11.16.0
  • pnpm: 12.10.1
  • teamai: 0.27.0
  • Provider: CNB (cnb.cool)
  • AI tool(s): CodeBuddy

Suggested fixes (any of)

  1. Detect the package manager. Read package.json#packageManager / presence of pnpm-lock.yaml / pnpm-workspace.yaml, and route to pnpm add [-g] / yarn add / bun add accordingly. (This is the "扩展位" the Proposal: teamai install — 统一编排 npm 依赖与 Claude 插件市场 #325 design reserved.)
  2. Add an explicit override (config key or flag) so a member can force the package manager for a project.
  3. Guard the npm path. When a foreign layout is detected (e.g. node_modules/.pnpm exists and the project declares pnpm), skip the npm adapter and warn rather than throw an opaque arborist crash.
  4. Nice-to-have: wrap the npm install failure so the error names the likely cause when a pnpm/yarn layout is present.

Logs

`teamai packages install typescript` (verbose)
npm error Cannot read properties of null (reading 'matches')
npm error A complete log of this run can be found in: /home/bladestone/.npm/_logs/2026-10-13T14_24_16_515Z-debug-0.log
file:///…/teamai-cli/dist/index.js:36059
            throw new Error(`npm install failed (exit ${result.code}): ${result.stderr.trim()}`);
                  ^
Error: npm install failed (exit 1): npm error Cannot read properties of null (reading 'matches')
    at NpmAdapter.install (file:///…/teamai-cli/dist/index.js:36059:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
    at async pkgInstall (file:///…/teamai-cli/dist/index.js:36516:7)
    at async run2 (file:///…/teamai-cli/dist/index.js:67881:3)
Node.js v24.18.0

npm debug log excerpt:

189 verbose stack TypeError: Cannot read properties of null (reading 'matches')
189 verbose stack     at Link.matches (…/@npmcli/arborist/lib/node.js:1183:41)
189 verbose stack     at Link.canDedupe (…/node.js:1127:15)
189 verbose stack     at PlaceDep.pruneDedupable (…/place-dep.js:426:14)
189 verbose stack     at new PlaceDep (…/place-dep.js:278:14)
189 verbose stack     at async Arborist.buildIdealTree (…/build-ideal-tree.js:995:18)
195 verbose cwd /path/to/pnpm-project
198 verbose npm  v11.16.0

Activity

  1. akushonkamen commented on Oct 14, 2026

    @akushonkamen

    I'd like to take this one.

    Root cause confirmed: NpmAdapter.install() unconditionally shells out to npm install with cwd set to the project root (src/pkg/adapters/npm.ts, the this.execute('npm', args, { cwd: context.cwd, ... }) call, ~L155). There is no package-manager detection (pnpm-workspace.yaml / packageManager field), and snapshotLocal() (~L74) only reads package-lock.json. I reproduced the arborist crash (Cannot read properties of null (reading 'matches'), exit 1) by running npm install --dry-run in a pnpm workspace with a transitive dependency tree — on both npm 11.9.0 and npm 11.16.0.

    Planned fix: detect a pnpm project (pnpm-workspace.yaml, pnpm-lock.yaml, or package.json#packageManager starting with pnpm) and route installs through pnpm add [-g] (snapshot via pnpm list --json), keeping the npm path byte-for-byte unchanged for non-pnpm projects.

    Disclaimer: I'm an AI-assisted contributor; the patch will be prepared with AI tooling and reviewed by a human (me) before submission.

  2. akushonkamen commented on Oct 14, 2026

    @akushonkamen

    PR opened: #1116 — detects pnpm (pnpm-workspace.yaml / pnpm-lock.yaml / packageManager field) and routes installs through pnpm add, with snapshots from pnpm list --json. npm path unchanged; red-to-green repro and test evidence in the PR description.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions