diff --git a/doc/api/errors.md b/doc/api/errors.md
index d99260107ad864..cb82facc4ed619 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1116,6 +1116,14 @@ added:
 
 An attempt to invoke an unsupported crypto operation was made.
 
+<a id="ERR_CWD_DELETED"></a>
+
+### `ERR_CWD_DELETED`
+
+The current working directory has been deleted while the process was still inside it.
+
+To resolve this, use `process.chdir()` to switch to a valid directory.
+
 <a id="ERR_DEBUGGER_ERROR"></a>
 
 ### `ERR_DEBUGGER_ERROR`
diff --git a/lib/internal/bootstrap/switches/does_own_process_state.js b/lib/internal/bootstrap/switches/does_own_process_state.js
index 370da66a825f65..5528df3338e3de 100644
--- a/lib/internal/bootstrap/switches/does_own_process_state.js
+++ b/lib/internal/bootstrap/switches/does_own_process_state.js
@@ -138,7 +138,8 @@ function wrappedUmask(mask) {
 }
 
 function wrappedCwd() {
-  if (cachedCwd === '')
+  if (cachedCwd === '') {
     cachedCwd = rawMethods.cwd();
+  }
   return cachedCwd;
 }
diff --git a/src/node_errors.h b/src/node_errors.h
index 9127dd79f1faf4..ae9bc1f553ed37 100644
--- a/src/node_errors.h
+++ b/src/node_errors.h
@@ -37,6 +37,7 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details);
 
 #define ERRORS_WITH_CODE(V)                                                    \
   V(ERR_ACCESS_DENIED, Error)                                                  \
+  V(ERR_CWD_DELETED, Error)                                                    \
   V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, Error)                                   \
   V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError)                                      \
   V(ERR_BUFFER_TOO_LARGE, Error)                                               \
@@ -172,6 +173,10 @@ ERRORS_WITH_CODE(V)
   V(ERR_ACCESS_DENIED, "Access to this API has been restricted")               \
   V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE,                                          \
     "Buffer is not available for the current Context")                         \
+  V(ERR_CWD_DELETED,                                                           \
+    "Current working directory does not exist. "                               \
+    "It may have been deleted while the process was still "                    \
+    "inside it. Use process.chdir() to change to a valid directory.")          \
   V(ERR_CLOSED_MESSAGE_PORT, "Cannot send data on closed MessagePort")         \
   V(ERR_CONSTRUCT_CALL_INVALID, "Constructor cannot be called")                \
   V(ERR_CONSTRUCT_CALL_REQUIRED, "Cannot call constructor without `new`")      \
diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc
index f6f552b807e71c..a37413af50debd 100644
--- a/src/node_process_methods.cc
+++ b/src/node_process_methods.cc
@@ -159,6 +159,10 @@ static void Cwd(const FunctionCallbackInfo<Value>& args) {
   char buf[PATH_MAX_BYTES];
   size_t cwd_len = sizeof(buf);
   int err = uv_cwd(buf, &cwd_len);
+  if (err == UV_ENOENT) {
+    THROW_ERR_CWD_DELETED(env);
+    return;
+  }
   if (err) {
     return env->ThrowUVException(err, "uv_cwd");
   }
diff --git a/test/parallel/test-process-cwd-deleted.js b/test/parallel/test-process-cwd-deleted.js
new file mode 100644
index 00000000000000..c54c0cd809442f
--- /dev/null
+++ b/test/parallel/test-process-cwd-deleted.js
@@ -0,0 +1,36 @@
+'use strict';
+
+// This test verifies that an appropriate error is thrown when the current
+// working directory is deleted and process.cwd() is called.
+//
+// We do this by spawning a forked process and deleting the tmp cwd
+// while it is starting up.
+
+const common = require('../common');
+
+const { fork } = require('node:child_process');
+const { rmSync } = require('node:fs');
+const { strictEqual, ok } = require('node:assert');
+const { Buffer } = require('node:buffer');
+
+if (process.argv[2] === 'child') {
+  return;
+}
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+const tmpDir = tmpdir.path;
+
+const proc = fork(__filename, ['child'], {
+  cwd: tmpDir,
+  silent: true,
+});
+proc.on('spawn', common.mustCall(() => rmSync(tmpDir, { recursive: true })));
+
+proc.on('exit', common.mustCall((code) => {
+  strictEqual(code, 1);
+  proc.stderr.toArray().then(common.mustCall((chunks) => {
+    const buf = Buffer.concat(chunks);
+    ok(/Current working directory does not exist/.test(buf.toString()));
+  }));
+}));
\ No newline at end of file