Commit 5e893ce0725 for nodejs

commit 5e893ce0725de12d7cb6df79ebb4b6d813648328
Author: Joyee Cheung <joyeec9h3@gmail.com>
Date:   Thu Nov 5 16:21:41 2026 +0100

    src: do not enable the inspector during snapshot building

    V8 no longer allows attaching a debuger or setting a debug context ID
    during snapshot building. Avoid enabling the inspector in this case,
    and reject the inspector options when the user-land --build-snapshot
    is used.

    Refs: https://chromium-review.googlesource.com/c/v8/v8/+/8679045
    Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com>
    PR-URL: https://github.com/nodejs/node/pull/67154
    Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
    Reviewed-By: Richard Lau <richard.lau@ibm.com>

diff --git a/doc/api/cli.md b/doc/api/cli.md
index d3309ae6192..415b65ac5ef 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -721,6 +721,10 @@ an additional module during the snapshot building process is needed,
 please file a request in the [Node.js issue tracker][] and link to it in the
 [tracking issue for user-land snapshots][].

+During snapshot building, a debugger cannot be attached to the process.
+`--build-snapshot` cannot be used together with `--inspect`, `--inspect-brk` or
+`--inspect-wait`.
+
 ### `--build-snapshot-config`

 <!-- YAML
diff --git a/doc/node.1 b/doc/node.1
index 444da29eed3..7419eb9a34d 100644
--- a/doc/node.1
+++ b/doc/node.1
@@ -447,6 +447,9 @@ runtime, using either \fBv8.startupSnapshot.setDeserializeMainFunction()\fR or
 an additional module during the snapshot building process is needed,
 please file a request in the Node.js issue tracker and link to it in the
 tracking issue for user-land snapshots.
+During snapshot building, a debugger cannot be attached to the process.
+\fB--build-snapshot\fR cannot be used together with \fB--inspect\fR, \fB--inspect-brk\fR or
+\fB--inspect-wait\fR.
 .
 .It Fl -build-snapshot-config
 Specifies the path to a JSON configuration file which configures snapshot
diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc
index 22506e26b32..cfa2f2adb9d 100644
--- a/src/inspector_agent.cc
+++ b/src/inspector_agent.cc
@@ -528,7 +528,11 @@ class NodeInspectorClient : public V8InspectorClient {
         is_main_ ? GetHumanReadableProcessName() : GetWorkerLabel(env);
     ContextInfo info(name);
     info.is_default = true;
-    contextCreated(env->context(), info);
+    // V8 does not allow a debugger to be attached while a startup or
+    // a debug context ID to be set during snapshot building.
+    if (!env->isolate_data()->is_building_snapshot()) {
+      contextCreated(env->context(), info);
+    }
   }

   void runMessageLoopOnPause(int context_group_id) override {
@@ -923,6 +927,12 @@ bool Agent::StartIoThread() {

   CHECK_NOT_NULL(client_);

+  if (parent_env_->isolate_data()->is_building_snapshot()) {
+    fprintf(stderr,
+            "The inspector cannot be activated while building a snapshot.\n");
+    return false;
+  }
+
   io_ = InspectorIo::Start(client_->getThreadHandle(),
                            path_,
                            host_port_,
diff --git a/src/node_options.cc b/src/node_options.cc
index 4ba4801ad1d..e141fab9e82 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -203,23 +203,16 @@ void PerProcessOptions::CheckProcessTimeoutOptions(
   // make the timeout fire while the debugger is in control, so the two cannot
   // be combined. Runtime activation of the inspector is rejected separately.
   const DebugOptions& debug_options = per_isolate->per_env->debug_options();
-  const char* debug_option = nullptr;
-  if (debug_options.break_node_first_line) {
-    debug_option = "--inspect-brk-node";
-  } else if (debug_options.break_first_line) {
-    debug_option = "--inspect-brk";
-  } else if (debug_options.inspect_wait) {
-    debug_option = "--inspect-wait";
-  } else if (debug_options.inspector_enabled) {
-    debug_option = "--inspect";
-  } else if (debug_options.host_port.host() != "127.0.0.1" ||
-             debug_options.host_port.port() !=
-                 DebugOptions::kDefaultInspectorPort) {
-    // We can't catch the case where the value passed is the default value,
-    // then the option just becomes a noop which is fine.
-    debug_option = "--inspect-port";
-  } else if (debug_options.inspect_publish_uid_string != "stderr,http") {
-    debug_option = "--inspect-publish-uid";
+  const char* debug_option = debug_options.inspector_option_name();
+  if (debug_option == nullptr) {
+    if (debug_options.host_port.host() != "127.0.0.1" ||
+        debug_options.host_port.port() != DebugOptions::kDefaultInspectorPort) {
+      // We can't catch the case where the value passed is the default value,
+      // then the option just becomes a noop which is fine.
+      debug_option = "--inspect-port";
+    } else if (debug_options.inspect_publish_uid_string != "stderr,http") {
+      debug_option = "--inspect-publish-uid";
+    }
   }
   if (debug_option != nullptr) {
     errors->push_back(std::string("either --process-timeout or ") +
@@ -297,6 +290,16 @@ void PerIsolateOptions::CheckOptions(std::vector<std::string>* errors,
     HandleMaxOldSpaceSizePercentage(errors, &max_old_space_size_percentage);
   }

+  if (build_snapshot) {
+    // V8 does not allow a debugger to be attached during snapshot building.
+    const char* debug_option = per_env->debug_options().inspector_option_name();
+    if (debug_option != nullptr) {
+      errors->push_back(
+          std::string("--build-snapshot cannot be used together with ") +
+          debug_option);
+    }
+  }
+
   per_env->CheckOptions(errors, argv);
 }

diff --git a/src/node_options.h b/src/node_options.h
index f8aa5825386..d28560c5a53 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -112,6 +112,14 @@ class DebugOptions : public Options {
     return break_first_line || break_node_first_line;
   }

+  const char* inspector_option_name() const {
+    if (break_node_first_line) return "--inspect-brk-node";
+    if (break_first_line) return "--inspect-brk";
+    if (inspect_wait) return "--inspect-wait";
+    if (inspector_enabled) return "--inspect";
+    return nullptr;
+  }
+
   void CheckOptions(std::vector<std::string>* errors,
                     std::vector<std::string>* argv) override;
 };
diff --git a/test/parallel/test-inspect-address-in-use.js b/test/parallel/test-inspect-address-in-use.js
index bd954e4a7bc..9c97aeabf3a 100644
--- a/test/parallel/test-inspect-address-in-use.js
+++ b/test/parallel/test-inspect-address-in-use.js
@@ -42,9 +42,14 @@ function testChildProcess(getArgs, exitCode, options) {

 tmpdir.refresh();

-testChildProcess(
-  (port) => [`--inspect=${port}`, '--build-snapshot', entry], 0,
-  { cwd: tmpdir.path });
+// V8 does not allow a debugger to be attached during snapshot building.
+spawnSyncAndExit(process.execPath, ['--inspect=0', '--build-snapshot', entry],
+                 { cwd: tmpdir.path },
+                 {
+                   status: 9,
+                   signal: null,
+                   stderr: /--build-snapshot cannot be used together with --inspect/,
+                 });

 testChildProcess(
   (port) => [`--inspect=${port}`, entry], 0);
diff --git a/test/parallel/test-snapshot-console.js b/test/parallel/test-snapshot-console.js
index 4acc804b201..b65014da989 100644
--- a/test/parallel/test-snapshot-console.js
+++ b/test/parallel/test-snapshot-console.js
@@ -30,7 +30,10 @@ const entry = fixtures.path('snapshot', 'console.js');
     console.log(child.stderr.toString());
     assert.strictEqual(child.status, 0);
   }
-  assert.deepStrictEqual(Object.keys(console), JSON.parse(stdout));
+  // console.createTask is not available during snapshot buildling.
+  assert.deepStrictEqual(
+    Object.keys(console).filter((key) => key !== 'createTask'),
+    JSON.parse(stdout));
   const stats = fs.statSync(tmpdir.resolve('snapshot.blob'));
   assert(stats.isFile());
 }