Repository navigation
[Bug] ENOENT uv_cwd error dump when working directory is deleted and latest_unavailable in GUI #3400
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't workingcliCLI, config inject, packaging flagsCLI, config inject, packaging flagsguiDashboard, tray, settings UIDashboard, tray, settings UI
Description
Client or integration
CLI
Area
CLI
Summary
Running ocx or ocx start from a working directory that has been deleted or unlinked causes two chained failures:
- Startup crash dump to stderr: in src/update/notify.ts and src/cli/star-prompt.ts, checking process.stdin.isTTY triggers Bun's lazy initialization of new tty.ReadStream(0). Bun's stream constructor attempts to validate path "" against process.cwd(). Because the working directory was unlinked, libuv's uv_cwd fails with ENOENT: process.cwd failed with error no such file or directory, uv_cwd.
- Dashboard update check failure: the proxy daemon remains running in the background with a deleted cwd. When the GUI dashboard queries GET /api/update/check?tag=latest, the server executes spawnSync for npm view. Because the parent process cwd is deleted, spawnSync fails, returning latestVersion: null and reason "latest_unavailable". The dashboard displays: "Could not read the latest version from npm. Try again later."
Reproduction
- Open a terminal and create a temporary directory:
mkdir -p /tmp/stale-workdir && cd /tmp/stale-workdir - Remove that directory from another process or terminal window:
rmdir /tmp/stale-workdir - Run ocx start in the original terminal.
- Observe the ENOENT process.cwd error dump from internal:fs/streams via interactiveGuardOk.
- Open the dashboard update modal at http://localhost:10100/ and observe that the latest version check fails with reason latest_unavailable.
Version
2.41.0
Operating system
macOS 15.x / Linux / POSIX
Provider and model
N/A
Logs or error output
53 | function ReadStream(path, options) {
54 | if (!(this instanceof ReadStream))
55 | return new ReadStream(path, options);
56 | options = copyObject(getStreamOptions(options)), options.decodeStrings = !0;
57 | let { fd, autoClose, fs: customFs, start, end = @Infinity } = options;
58 | this[kFs] = customFs || fs, this.fd = null, this.path = getValidatedPath(path);
^
error: ENOENT: process.cwd failed with error no such file or directory, the current working directory was likely removed without changing the working directory, uv_cwd
at ReadStream (internal:fs/streams:58:77)
at new ReadStream (node:tty:11:23)
at interactiveGuardOk (.../src/update/notify.ts:126:40)
at shouldConsider (.../src/update/notify.ts:139:8)
at maybeShowUpdatePrompt (.../src/update/notify.ts:233:22)
at handleStart (.../src/cli/index.ts:310:9)Redacted configuration
No response
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingcliCLI, config inject, packaging flagsCLI, config inject, packaging flagsguiDashboard, tray, settings UIDashboard, tray, settings UI
Activity
lidge-jun commentedon Sep 3, 2026
리뷰 · 우선순위 54 / 80
이 이슈는
ocx/ocx start를 이미 지워진(또는 unlink된) 작업 디렉터리에서 실행했을 때 생기는 두 갈래 고장이에요. 지금devHEAD(b2954397b, GUI page polish #3397까지)에는 아직 이 방어가 없습니다.첫 번째 갈래는 CLI 시작 직후입니다.
src/update/notify.ts의interactiveGuardOk()와src/cli/star-prompt.ts의maybeShowStarPrompt()가process.stdin.isTTY/process.stdout.isTTY를 읽습니다. Bun에서는 이 접근이 게으르게new tty.ReadStream(0)을 만들고, 스트림 생성자가 빈 path를process.cwd()기준으로 검사합니다. cwd가 이미 사라졌으면 libuvuv_cwd가ENOENT를 내고, 호출자 try/catch보다 먼저 stderr에 긴 덤프가 찍힙니다. 재현 경로(임시 폴더 만들고 다른 창에서rmdir한 뒤 같은 셸에서ocx start)도 명확합니다.두 번째 갈래는 프록시가 그 깨진 cwd를 그대로 물고 살아남을 때입니다. 대시보드가
GET /api/update/check?tag=latest를 치면 서버 쪽이npm view를spawnSync로 돌리는데, 자식이 부모의 삭제된 cwd를 물려받으면 실패하고latestVersion: null+ reasonlatest_unavailable이 됩니다. GUI에는 “Could not read the latest version from npm…” 문구로 보입니다. 즉 CLI 덤프뿐 아니라 업데이트 배지/모달까지 같이 깨지는 연쇄입니다.지금
dev에서 관련 코드는 아직 예전 형태입니다.notify.ts의interactiveGuardOk는process.stdin.isTTY를 쓰고,star-prompt.ts도 같고,bin/ocx.mjs/src/cli/index.ts맨 앞에 cwd 복구가 없습니다. 고쳐 주는 PR은 #3401(fix/heal-deleted-cwd-and-isatty-guard)이고, Closes #3400으로 이미 묶여 있습니다. types.ts/config.ts 분할 캠페인과는 무관해서 close-don't-rebase 대상이 아닙니다.우선순위 54로 둔 이유는, 재현이 확실하고 사용자에게 보이는 실패지만, “폴더를 지운 뒤 그 셸에서 계속 실행”이라는 비교적 드문 POSIX 엣지라서 지금
dev의 GUI polish 메인 트레인(#3397/#3396/#3395…)보다는 한 칸 아래이기 때문입니다. 그래도 CLI+GUI가 같이 깨지므로 “나중에 하자” 수준은 아닙니다.라인 - (이슈라서 단일 라인 없음) 재현 스택의
interactiveGuardOk/maybeShowUpdatePrompt/handleStart로 이어지므로, 수정 검증은 “덤프 없음”뿐 아니라 대시보드 update check가latest_unavailable이 아닌지도 같이 봐야 합니다.경로/심볼 -
src/update/notify.tsinteractiveGuardOk·src/cli/star-prompt.tsmaybeShowStarPrompt· 업데이트 체크의spawnSync(src/update/job/index 쪽)가 이 이슈의 핵심 세 지점입니다.경로/심볼 - 버전 표기는 2.41.0이지만 현재
devpackage는 2.42.0 라인입니다. 동작 자체는 HEAD에도 동일하게 남아 있을 가능성이 큽니다(위 코드가 아직 예전 형태).메인테이너의 판단이 필요한 지점
너의 추천
dev에 들어가면 Closes로 같이 닫히게 두면 됩니다.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 4, 2026
Fixed by #3401, squash-merged into
devas 0f2e120.Both chained failures are addressed. The TTY guard now probes
isatty(0)/isatty(1)instead ofprocess.stdin.isTTY, so Bun never lazily constructstty.ReadStreamagainst the unlinked working directory and the ENOENTuv_cwddump is gone. Both launch paths recover tohomedir()whencwd()fails, so the daemon's laternpm viewsubprocess inherits a valid directory and the dashboard update check stops reportinglatest_unavailable.One follow-up worth noting: the regression in
tests/update-notify.test.tscovers the TTY guard under an unlinked cwd but does not spawn a launcher, so the cwd healing itself is not yet asserted end to end.Closing manually: these pull requests target
dev, and GitHub only auto-closes linked issues on the default branch.Thanks @agentHits.
fix(tests): repair two dev regressions from the 260904 merge train (#…
fix(tests): repair two dev regressions from the 260904 merge train (l…