From 5f6abb0b1ad93791b23984695a775bc96af180cd Mon Sep 17 00:00:00 2001 From: VitaliPri Date: Tue, 27 Jan 2026 22:58:25 -0500 Subject: [PATCH] fix: throw clear error when cwd directory does not exist When using a non-existent cwd directory, zx now throws a descriptive error message instead of failing with a cryptic spawn error. This makes debugging easier by immediately telling users what's wrong. Fixes #1386 Co-Authored-By: Claude Opus 4.5 --- .size-limit.json | 6 +++--- src/core.ts | 10 ++++++++++ test/core.test.js | 19 ++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/.size-limit.json b/.size-limit.json index 29051427c8..ce17a975be 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -19,7 +19,7 @@ "README.md", "LICENSE" ], - "limit": "129.25 kB", + "limit": "129.60 kB", "brotli": false, "gzip": false }, @@ -33,7 +33,7 @@ "build/globals.js", "build/deno.js" ], - "limit": "847.80 kB", + "limit": "848.15 kB", "brotli": false, "gzip": false }, @@ -66,7 +66,7 @@ "README.md", "LICENSE" ], - "limit": "909.40 kB", + "limit": "909.75 kB", "brotli": false, "gzip": false } diff --git a/src/core.ts b/src/core.ts index 94acee83cb..969f330dfe 100644 --- a/src/core.ts +++ b/src/core.ts @@ -289,6 +289,16 @@ export class ProcessPromise extends Promise { throw new Fail(`No quote function is defined: ${Fail.DOCS_URL}/quotes`) if ($.pieces.some((p) => p == null)) throw new Fail(`Malformed command at ${$.from}`) + if ($.cwd) { + try { + const stat = fs.statSync($.cwd) + if (!stat.isDirectory()) + throw new Fail(`The cwd option is not a directory: ${$.cwd}`) + } catch (err) { + if (err instanceof Fail) throw err + throw new Fail(`The cwd directory does not exist: ${$.cwd}`) + } + } $.cmd = buildCmd( $.quote!, diff --git a/test/core.test.js b/test/core.test.js index 985b7e382d..cfca1959f1 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -256,15 +256,28 @@ describe('core', () => { assert.match(err[inspect.custom](), /Command not found/) }) - test('error event is handled', async () => { + test('error is thrown for non-existent cwd', async () => { await within(async () => { $.cwd = 'wtf' try { await $`pwd` assert.unreachable('should have thrown') } catch (err) { - assert.ok(err instanceof ProcessOutput) - assert.match(err.message, /No such file or directory/) + assert.ok(err instanceof Fail) + assert.match(err.message, /The cwd directory does not exist: wtf/) + } + }) + }) + + test('error is thrown when cwd is a file', async () => { + await within(async () => { + $.cwd = './README.md' + try { + await $`pwd` + assert.unreachable('should have thrown') + } catch (err) { + assert.ok(err instanceof Fail) + assert.match(err.message, /The cwd option is not a directory/) } }) })