Skip to content

fix(ci): replace tsc --build with tsc --composite false to prevent race condition#12493

Closed
davidkonigsberg wants to merge 1 commit intomainfrom
devin/1771352773-fix-tsc-build-race-condition
Closed

fix(ci): replace tsc --build with tsc --composite false to prevent race condition#12493
davidkonigsberg wants to merge 1 commit intomainfrom
devin/1771352773-fix-tsc-build-race-condition

Conversation

@davidkonigsberg
Copy link
Copy Markdown
Contributor

@davidkonigsberg davidkonigsberg commented Feb 17, 2026

Description

Refs: Failed CI job — intermittent @fern-api/ir-utils:compile failure with:

'"@fern-api/ir-sdk"' has no exported member named 'ExampleInlinedRequestBodyProperty'.
Did you mean 'ExampleInlinedRequestBodyExtraProperty'?

The type exists in ir-sdk source and the error disappears on re-run.

Requested by: @davidkonigsberg
Link to Devin run: https://app.devin.ai/sessions/c176a6d6126b4616b03415f9af267f95

Root Cause Analysis

When turbo runs compile tasks, it respects dependsOn: ["^compile"] for ordering but runs sibling tasks concurrently. Each package's tsc --build follows project references in tsconfig.json and checks whether referenced projects need rebuilding. 25+ packages reference ir-sdk. If any concurrent tsc --build process decides ir-sdk is stale and starts rewriting its lib/ output, other concurrent processes reading from ir-sdk/lib/ can see incomplete declarations.

Changes Made

  • compile: tsc --buildtsc --composite false (174 packages)
  • compile:debug: tsc --build --sourceMaptsc --composite false --sourceMap (171 packages)
  • clean: tsc --build --cleanrm -f tsconfig.tsbuildinfo (175 packages)

tsc --composite false overrides the composite: true from tsconfig.json, causing tsc to compile only the current package without following project references. Turbo still handles build ordering via dependsOn: ["^compile"].

⚠️ Human Review Checklist

This is a large mechanical change. Please scrutinize the approach, not just the diff.

  • Is the root cause correct? The race condition theory is plausible but was not definitively proven — only inferred from log timing analysis and the fact that tsc --build follows references. The flake could have other causes (infra, turbo bug, etc.).
  • Is tsc --composite false the right pattern? This is an uncommon approach. It disables composite at the CLI level while tsconfig.json still says composite: true. This means: (a) no .tsbuildinfo files → no incremental compilation, (b) references in tsconfig become dead config, (c) IDE behavior may diverge from build behavior.
  • Impact on local dev? Every pnpm run compile in a package will now do a full recompile (no incremental builds). Turbo cache helps in CI but not for local iterative development.
  • Are there packages that rely on .tsbuildinfo for other tools? The clean script now does rm -f tsconfig.tsbuildinfo but tsc --composite false doesn't generate it anyway.
  • Module resolution edge cases? With tsc --build, TypeScript uses project references for resolution. With tsc --composite false, it uses normal node_modules resolution. Tested on ir-sdk and ir-utils but not all 175 packages.

Testing

  • Local test: ir-sdk and ir-utils compile successfully with tsc --composite false
  • Local test: turbo run compile --filter=@fern-api/ir-utils (7 packages) passes
  • Full monorepo compile (will be tested in CI)
  • Seed tests (will be tested in CI)

Alternative Approaches Considered

  1. Use tsc without --composite false: Doesn't work — tsc respects composite: true in tsconfig and requires --build flag.
  2. Remove composite: true from all tsconfig.json files: More invasive; affects IDE behavior and requires updating 175+ tsconfig files.
  3. Serialize compilation with turbo concurrency limits: Would significantly slow down CI.
  4. Fix the actual race in tsc --build: Not feasible — this is TypeScript compiler behavior.

Open with Devin

…ce condition

When turbo runs concurrent compile tasks, multiple tsc --build processes
can follow project references to the same upstream package (e.g. ir-sdk).
If any downstream tsc --build decides to rebuild a shared reference,
concurrent reads from other processes see incomplete output, causing
intermittent type errors like:

  '"@fern-api/ir-sdk"' has no exported member named
  'ExampleInlinedRequestBodyProperty'

By using tsc --composite false instead of tsc --build:
- Each package only compiles its own source files
- No project reference following or upstream rebuilding
- Turbo still handles build order via dependsOn: ["^compile"]
- Eliminates the entire class of concurrent tsc --build race conditions

Co-Authored-By: David Konigsberg <davidakonigsberg@gmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@davidkonigsberg davidkonigsberg deleted the devin/1771352773-fix-tsc-build-race-condition branch February 19, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant