Skip to content

squad-cli fails with ERR_MODULE_NOT_FOUND on Node 22 (vscode-jsonrpc ESM import) #449

Closed

Description

@uvirk

Description

Running npx @bradygaster/squad-cli on Node 22 fails with an ESM module resolution error.

Error

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/...node_modules/vscode-jsonrpc/node' imported from '/...node_modules/@github/copilot-sdk/dist/session.js' Did you mean
to import "vscode-jsonrpc/node.js"?

Cause

@github/copilot-sdk imports vscode-jsonrpc/node without the .js extension, which fails under Node 22's strict ESM resolution.

Workaround

NODE_OPTIONS="--experimental-specifier-resolution=node" npx @bradygaster/squad-cli

Environment

  • Node.js 22
  • npm (via npx)
  • @bradygaster/squad-cli@0.8.25
  • Fedora (toolbox container)

Activity

  1. github-actions commented on Mar 18, 2026

    @github-actions
    Contributor

    🏗️ Squad Triage — Flight (Lead)

    Issue: #449 — squad-cli fails with ERR_MODULE_NOT_FOUND on Node 22 (vscode-jsonrpc ESM import)
    Assigned to: Flight (Lead)
    Reason: No specific domain match — assigned to Lead for further analysis

    @copilot evaluation: No strong capability match — routed to squad member.

    Team roster:

    • Flight (Lead) → label: squad:flight
    • Procedures (Prompt Engineer) → label: squad:procedures
    • EECOM (Core Dev) → label: squad:eecom
    • FIDO (Quality Owner) → label: squad:fido
    • PAO (DevRel) → label: squad:pao
    • CAPCOM (SDK Expert) → label: squad:capcom
    • CONTROL (TypeScript Engineer) → label: squad:control
    • Surgeon (Release Manager) → label: squad:surgeon
    • Booster (CI/CD Engineer) → label: squad:booster
    • GNC (Node.js Runtime) → label: squad:gnc
    • Network (Distribution) → label: squad:network
    • RETRO (Security) → label: squad:retro
    • INCO (CLI UX & Visual Design) → label: squad:inco
    • GUIDO (VS Code Extension) → label: squad:guido
    • Telemetry (Aspire & Observability) → label: squad:telemetry
    • VOX (REPL & Interactive Shell) → label: squad:vox
    • DSKY (TUI Engineer) → label: squad:dsky
    • Sims (E2E Test Engineer) → label: squad:sims
    • Handbook (SDK Usability) → label: squad:handbook
    • Ralph (Work Monitor) → label: squad:ralph
    • @copilot (Coding Agent) → label: squad:copilot

    To reassign, remove the current squad:* label and add the correct one.

  2. github-actions commented on Mar 18, 2026

    @github-actions
    Contributor

    📋 Assigned to GNC (Node.js Runtime)

    Issue: #449 — squad-cli fails with ERR_MODULE_NOT_FOUND on Node 22 (vscode-jsonrpc ESM import)

    GNC will pick this up in the next Copilot session.

    For Copilot coding agent: If enabled, this issue will be worked automatically.
    Otherwise, start a Copilot session and say:
    GNC, work on issue #449

  3. alefranz commented on Mar 19, 2026

    @alefranz

    same issue on Node 24, where also the suggested workaround doesn't work

  4. bradygaster commented on Mar 20, 2026

    @bradygaster
    Collaborator

    🔬 Flight Research: Node 22+ ESM Module Resolution Failure

    Root Cause Analysis

    The bug has three contributing factors:

    1. vscode-jsonrpc@8.2.1 has no exports field — Without an exports map, Node.js ESM resolves subpath imports (vscode-jsonrpc/node) as literal filesystem paths. The file node_modules/vscode-jsonrpc/node.js exists but is a CJS wrapper (module.exports = require('./lib/node/main')). In strict ESM, vscode-jsonrpc/node (no extension) fails because Node won't auto-append .js.

    2. @github/copilot-sdk@0.1.32 has inconsistent imports — session.js imports vscode-jsonrpc/node (broken, no .js), while client.js imports vscode-jsonrpc/node.js (correct). This inconsistency means some code paths work and others don't.

    3. Node 22+ enforces strict ESM resolution — Node 22 (LTS since Oct 2024) no longer auto-resolves extensionless subpath imports in ESM packages. Node 24 goes further: --experimental-specifier-resolution=node is removed entirely (confirmed by @alefranz).

    Confirmed locally on Node 22.16.0:

    ✅ import('vscode-jsonrpc/node.js')  → works
    ❌ import('vscode-jsonrpc/node')     → ERR_MODULE_NOT_FOUND
    

    Current State of Fix

    v0.8.23 shipped a two-layer fix (commit a120484):

    • Layer 1: Lazy imports in cli-entry.ts (commands that don't need copilot-sdk skip the broken import)
    • Layer 2: postinstall script that patches copilot-sdk's session.js to add .js extension

    Why users still hit this:

    • npx does not always run postinstall scripts (security restrictions, --ignore-scripts, or npm configuration)
    • The patch targets only session.js — future copilot-sdk updates may introduce more extensionless imports
    • Node 24 users can't use the NODE_OPTIONS workaround at all

    Node 22 Impact

    • Node 22 = Active LTS (since Oct 29, 2024, through Oct 2025; maintenance through Apr 2027)
    • It's the recommended production Node version for 2025
    • Our engines field says >=20 — Node 22 is squarely in our support range
    • This is a P1 bug that blocks all Node 22+ users who don't have postinstall enabled

    Upstream Status

    Package Version Status
    vscode-jsonrpc 8.2.1 (stable) ❌ No exports field
    vscode-jsonrpc 9.0.0-next.11 (prerelease) ✅ Has proper exports
    @github/copilot-sdk 0.1.32 (stable) ❌ Broken import in session.js
    @github/copilot-sdk 0.1.33-* (preview/unstable) ❌ Still uses vscode-jsonrpc@^8.2.1

    Options — Ranked by Effort/Risk

    # Option Effort Risk Node 22 Node 24 Notes
    A Patch vscode-jsonrpc's package.json (add exports) Low Low ✅ ✅ Fixes ALL subpath imports at the source. More robust than patching individual copilot-sdk files.
    B Improve existing postinstall to also patch vscode-jsonrpc Low Low ✅ ✅ Defense-in-depth alongside Option A
    C Custom ESM loader hook (--loader) Med Med ✅ ✅ Intercepts resolution for extensionless imports. Maintenance burden.
    D Bundle copilot-sdk with esbuild High High ✅ ✅ Resolves at build time. Changes build pipeline significantly.
    E Add NODE_OPTIONS to bin shebang Low High ✅ ❌ --experimental-specifier-resolution=node removed in Node 24
    F Wait for upstream copilot-sdk/vscode-jsonrpc fix Zero Very High ❓ ❓ vscode-jsonrpc 9.x is pre-release; no timeline. copilot-sdk 0.1.33 still uses ^8.2.1.

    Recommended Approach

    Dual-layer hardening (Options A + B):

    Layer 1 — Patch vscode-jsonrpc/package.json at postinstall to inject the exports field from v9.x:

    {
      "exports": {
        ".": { "types": "./lib/common/api.d.ts", "default": "./lib/node/main.js" },
        "./node": { "node": "./lib/node/main.js", "types": "./lib/node/main.d.ts" },
        "./browser": { "types": "./lib/browser/main.d.ts", "browser": "./lib/browser/main.js" }
      }
    }

    This fixes the root cause (missing exports) rather than chasing individual import sites.

    Layer 2 — Keep the existing copilot-sdk session.js patch as defense-in-depth for edge cases.

    Layer 3 — Document Node 22+ requirement in README and squad doctor should check for this.

    Acceptance Criteria

    • npx @bradygaster/squad-cli works on Node 22 without NODE_OPTIONS
    • npx @bradygaster/squad-cli works on Node 24 without any workarounds
    • squad doctor detects and reports the ESM resolution issue if postinstall failed
    • Postinstall script patches vscode-jsonrpc/package.json exports field
    • Postinstall script continues to patch copilot-sdk session.js as backup
    • CI matrix includes Node 22 and Node 24 for smoke tests
    • Issue comment references the upstream root cause for tracking

    Assignment

    This is GNC domain (Node.js runtime compatibility). The postinstall patch approach is proven (we already ship one). Effort: ~1 day for the enhanced patch + doctor check + CI matrix update.


    — Flight (Lead), deep research on #449

  5. sturlath commented on Apr 2, 2026

    @sturlath
    Contributor

    I could not get this to work until I run the following command. Hope this helps someboydy

    # Go to repo
    Set-Location C:\mycode
    
    # Clean any old/global Squad installs
    npm uninstall -g @bradygaster/squad-cli @bradygaster/squad-sdk
    npm cache verify
    npm config set ignore-scripts false
    
    # Clean local repo install
    Remove-Item -Recurse -Force node_modules, package-lock.json -ErrorAction SilentlyContinue
    
    # Make Squad config portable
    @'
    {
      "version": 1,
      "teamRoot": "."
    }
    '@ | Set-Content .squad\config.json
    
    # Install Squad the npm way (global CLI, no npx)
    npm install -g @bradygaster/squad-cli@0.9.1
    # the is an error with doing it currently with the insider version npm install @bradygaster/squad-cli@insider @bradygaster/squad-sdk@insider
    
    # Install local project dependencies
    npm install
    
    # Manual fix for known #449-style ESM/package issue if doctor still fails
    $sessionFile = "node_modules\@github\copilot-sdk\dist\session.js"
    $vscodePkg   = "node_modules\vscode-jsonrpc\package.json"
    
    if (Test-Path $sessionFile) {
      (Get-Content $sessionFile -Raw) `
        -replace 'from\s+["'']vscode-jsonrpc/node["'']', 'from "vscode-jsonrpc/node.js"' |
        Set-Content $sessionFile
    }
    
    if (Test-Path $vscodePkg) {
      $json = Get-Content $vscodePkg -Raw | ConvertFrom-Json
      if (-not $json.PSObject.Properties['exports']) {
        $json | Add-Member -NotePropertyName exports -NotePropertyValue @{
          "."      = "./lib/common/api.js"
          "./node" = "./node.js"
        }
      }
      $json | ConvertTo-Json -Depth 20 | Set-Content $vscodePkg
    }
    
    # Verify npm-installed CLI is the one being used
    where.exe squad
    squad --version
    squad doctor
  6. uvirk commented on Apr 2, 2026

    @uvirk
    Author

    @sturlath Did you run Squad upgrade?

  7. sturlath commented on Apr 3, 2026

    @sturlath
    Contributor

    @sturlath Did you run Squad upgrade?

    For the insider version? Because I beleve that is where I got the errors and reference to this PR.

    At least it does not help with the warnings (here below I did have 0.9.1 installed)

    PS C:\Dev\yoursite-templates> squad upgrade
    ✓ upgraded coordinator from 0.0.0-source to 0.9.1
    ✓ upgraded 29 squad-owned files
    ✓ upgraded squad workflows (11 files)
    ✓ Migrated skills to .copilot/skills: ci-validation-placement, client-script-guards, config-contract-testing, config-driven-sections, design-token-injection, i18n-locale-routing, project-conventions, squad-conventions
    ✓ ensured .gitignore (3 entries added)
    ✓ synced 28 skills to .copilot/skills/
    ✓ refreshed .squad/templates/

    Upgrade complete: v0.0.0-source → v0.9.1
    Privacy scrub applied to .squad/ files (email addresses removed)

    PS C:\Dev\yoursite-templates> squad doctor

    🩺 Squad Doctor
    ═══════════════

    Mode: remote

    ✅ .squad/ directory exists — directory present
    ✅ config.json valid — parses as JSON, schema OK
    ✅ team root resolves — resolved to C:\Dev\yoursite-templates
    ✅ team.md found with ## Members header — file present, header found
    ✅ routing.md found — file present
    ✅ agents/ directory exists — directory present (6 agents)
    ✅ casting/registry.json exists — file present, valid JSON
    ✅ decisions.md exists — file present
    ✅ Node.js ≥22.5.0 (node:sqlite) — v22.22.2 — node:sqlite available
    ⚠️ vscode-jsonrpc exports field — vscode-jsonrpc not found in node_modules
    ⚠️ copilot-sdk session.js ESM patch — @github/copilot-sdk not found in node_modules

    Summary: 9 passed, 0 failed, 2 warnings

  8. uvirk commented on Apr 3, 2026

    @uvirk
    Author

    @sturlath it looks like there has been some work from the Squad on this specific use case - are you specifically running Squad locally? The warnings are only problematic if you are not in Mode: remote

  9. sturlath commented on Apr 4, 2026

    @sturlath
    Contributor

    @sturlath it looks like there has been some work from the Squad on this specific use case - are you specifically running Squad locally? The warnings are only problematic if you are not in Mode: remote

    @uvirk I looked up remote mode here and I don't quite understand because I work with 2 repos that both have their own separate squad install. Sometimes I get one squad to create something that is cross repo.. but how is it set/removed?

  10. added a commit that references this issue on Nov 8, 2026
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

    go:needs-researchNeeds investigationnext-upPriority queue — next issues to workpriority:p1This sprintsquadSquad triage inbox — Lead will assign to a membertype:bugSomething broken

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions