turbo icon indicating copy to clipboard operation
turbo copied to clipboard

turbo ls --affected reports all packages changed due to false positive on root package.json when only workspace dependencies changed

Open linusnorton opened this issue 1 month ago • 1 comments

Verify canary release

  • [x] I verified that the issue exists in the latest Turborepo canary release.

Link to code that reproduces this issue

https://github.com/hmcts/expressjs-monorepo-template/pull/195

Which canary version will you have in your reproduction?

2.6.1-canary.3

Environment information

CLI:                                                                                                
        Version: 2.6.1-canary.3
        Path to executable: /workspaces/expressjs-monorepo-template/node_modules/turbo-linux-64/bin/turbo
        Daemon status: Not running
        Package manager: berry

     Platform:
        Architecture: x86_64
        Operating system: linux
        WSL: false
        Available memory (MB): 232781
        Available CPU cores: 128

     Environment:
        CI: None
        Terminal (TERM): xterm-256color
        Terminal program (TERM_PROGRAM): vscode
        Terminal program version (TERM_PROGRAM_VERSION): 1.106.1
        Shell (SHELL): /bin/bash
        stdin: false
     turbo 2.6.1-canary.3

Expected behavior

Turborepo incorrectly reports all packages as affected when only workspace dependencies (like sass) are updated in a Yarn workspaces monorepo. Despite git showing only 2 files changed (yarn.lock and apps/web/package.json), Turborepo's --affected flag marks all packages as changed due to detecting the root package.json as a DefaultGlobalFileChanged.

What Should Happen

When a workspace dependency like sass is updated from 1.94.0 to 1.94.2:

  • Only packages that actually depend on sass (directly or transitively) should be marked as affected
  • In this case: only @hmcts/web should be affected
  • The root package.json was NOT modified in the git commit

Actual behavior

urborepo reports all 11 packages as affected (4 apps + 7 libs), even though only @hmcts/web depends on sass.

The trace output reveals the issue:

[DEBUG] lockfile changed, have the previous content [DEBUG] changed files: ["libs/postgres-prisma/package.json", "apps/web/package.json", ".github/workflows/osv-scanner.yml", "package.json", "yarn.lock"] [DEBUG] global file changed [DEBUG] all packages changed: DefaultGlobalFileChanged { file: AnchoredSystemPathBuf("package.json") }

Turborepo is incorrectly treating the root package.json as changed, even though git diff confirms it was not modified.

To Reproduce

Real-World Example

This issue occurred in production CI:

  • PR: https://github.com/hmcts/expressjs-monorepo-template/pull/195
  • CI Run: https://github.com/hmcts/expressjs-monorepo-template/actions/runs/19528647337/job/55906458150?pr=195
  • Commit: Renovate bot updating sass from 1.94.0 to 1.94.2 in apps/web/package.json

Files Actually Changed (via git)

$ git diff origin/master --name-only
apps/web/package.json
yarn.lock
$ git diff origin/master --stat
apps/web/package.json |  2 +-
yarn.lock             | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)

Command Output

Running on the PR branch:

$ yarn turbo ls --affected --output=json

Result: All 11 packages reported as affected:
  {
    "packageManager": "berry",
    "packages": {
      "count": 11,
      "items": [
        { "name": "@hmcts/api", "path": "apps/api" },
        { "name": "@hmcts/cloud-native-platform", "path": "libs/cloud-native-platform" },
        { "name": "@hmcts/crons", "path": "apps/crons" },
        { "name": "@hmcts/express-govuk-starter", "path": "libs/express-govuk-starter" },
        { "name": "@hmcts/footer-pages", "path": "libs/footer-pages" },
        { "name": "@hmcts/onboarding", "path": "libs/onboarding" },
        { "name": "@hmcts/postgres", "path": "apps/postgres" },
        { "name": "@hmcts/postgres-prisma", "path": "libs/postgres-prisma" },
        { "name": "@hmcts/simple-router", "path": "libs/simple-router" },
        { "name": "@hmcts/web", "path": "apps/web" },
        { "name": "e2e-tests", "path": "e2e-tests" }
      ]
    }
  }

Additional context

Versions

  • Turborepo: 2.6.1
  • Yarn: 4.11.0
  • Node.js: 22.x
  • Platform: Linux (Ubuntu on GitHub Actions)
  • Package Manager: yarn (Yarn Berry with nodeLinker: node-modules)

Trace Output

$ TURBO_LOG_VERBOSITY=trace yarn turbo ls --affected 2>&1 | grep -E "changed files|all packages changed"

[DEBUG] lockfile changed, have the previous content
[DEBUG] changed files: ["libs/postgres-prisma/package.json", "apps/web/package.json", ".github/workflows/osv-scanner.yml", "package.json", "yarn.lock"]
[DEBUG] global file changed
[DEBUG] all packages changed: DefaultGlobalFileChanged { file: AnchoredSystemPathBuf("package.json") }

Key issue: Turborepo reports 5 files changed including package.json, but git only shows 2 files changed.

Dependency Information

Only @hmcts/web depends on sass:

$ grep -r "sass" apps/*/package.json libs/*/package.json
apps/web/package.json:    "sass": "1.94.2",
libs/express-govuk-starter/package.json:    "sass": "^1.90.0",  # (peerDependency)

No other apps (api, crons, postgres) depend on sass.

linusnorton avatar Nov 20 '25 08:11 linusnorton

Hello! Thank you for filing this extremely detailed bug report, which includes a clear reproduction link, environment details, and trace output.

The information you provided is excellent and points directly to the core problem: Turborepo's internal file change detection is diverging from the actual git diff output, specifically regarding the root package.json and potentially other files like libs/postgres-prisma/package.json and .github/workflows/osv-scanner.yml.

The key trace line confirms the immediate cause of the incorrect behavior: [DEBUG] all packages changed: DefaultGlobalFileChanged { file: AnchoredSystemPathBuf("package.json") }

If the root package.json is incorrectly flagged as a changed global file, it will naturally mark all packages as affected, regardless of the dependency graph.

This suggests an issue in how Turborepo's file tracking (which relies on Git plumbing like tree hashes and file contents) interacts with Yarn Berry's management of dependencies, or potentially a discrepancy in the Git reference used for comparison.

I would like to investigate why:

The root package.json is being flagged as changed when git diff shows it is clean.

Additional files (libs/postgres-prisma/package.json and .github/workflows/osv-scanner.yml) are appearing in the changed files list but not in your git diff --name-only.

This is a critical issue for monorepos relying on accurate affected detection.

Please assign this issue to me so I can begin a deep dive into the Git/FS interaction and internal file tracking logic.

shubhanshu2103 avatar Nov 26 '25 06:11 shubhanshu2103