← Back to PRs

#11470: fix: prevent gateway:watch race by passing --no-clean to tsdown

by apetresc open 2026-02-07 21:19 View on GitHub →
scripts stale
## Summary `pnpm gateway:watch` fails on startup with `ERR_MODULE_NOT_FOUND` because of a race condition introduced by the tsdown migration (`a03d852d6`, 2026-02-02). ### Root cause `scripts/watch-node.mjs` does the following: 1. Runs `tsdown` synchronously to populate `dist/` (succeeds) 2. Spawns `tsdown --watch` and `node --watch openclaw.mjs` **concurrently** The problem is that `tsdown --watch` defaults to `clean: true`, so the first thing it does on startup is **delete the entire `dist/` directory** ("Cleaning 369 files") before rebuilding. Meanwhile, the `node --watch` process is already trying to import from `dist/`, and hits: ``` Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../dist/entry.js' ``` This is a 100% reproduction rate — the initial sync build output is always wiped before the node process can use it. ### Why this wasn't caught earlier - The **previous compiler (`tsc`)** overwrote files in-place during rebuilds. The old `.js` files stayed in `dist/` throughout recompilation, so even with the same concurrent spawn pattern, the gateway could start using the stale-but-present output. The tsdown migration changed this behavior by introducing a clean step. - Most developers use `gateway:dev` (via `run-node.mjs`), which properly sequences build → run. The `gateway:watch` path is less exercised. ### Fix Pass `--no-clean` to `tsdown --watch`. The initial synchronous build already produces a clean `dist/`, so the watch process doesn't need to wipe it again. Subsequent incremental rebuilds from file changes are unaffected — tsdown only cleans on the initial watch startup. ## Test plan - [x] `pnpm gateway:watch` — gateway starts successfully, listens on port, channels connect - [x] Verified the initial sync build still populates `dist/` correctly - [x] Confirmed `tsdown --watch --no-clean` still picks up file changes for incremental rebuilds 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR updates `scripts/watch-node.mjs` so the `pnpm gateway:watch` workflow no longer races on startup after the tsdown migration. Concretely, the script still performs an initial synchronous `tsdown` build to populate `dist/`, but now spawns the watcher as `tsdown --watch --no-clean` so the watch process doesn’t delete `dist/` during its initial startup while `node --watch` is concurrently importing built entrypoints. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk. - Change is small, localized to a dev script, and directly addresses a deterministic startup failure by preventing the watcher from deleting the just-built `dist/` directory during concurrent Node startup. - No files require special attention <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs