Closed Bug 1956197 Opened 1 year ago Closed 1 year ago

TypeError: BigInt value can't be serialized in JSON

Categories

(DevTools :: Debugger, defect, P2)

defect

Tracking

(firefox138 fixed)

RESOLVED FIXED
138 Branch
Tracking Status
firefox138 --- fixed

People

(Reporter: tarek, Assigned: nchevobbe)

References

Details

Attachments

(2 files)

In Nightly, if you apply this patch:

diff --git a/toolkit/components/aboutinference/content/aboutInference.js b/toolkit/components/aboutinference/content/aboutInference.js
index f0c6e0296519c..ecc9319a716eb 100644
--- a/toolkit/components/aboutinference/content/aboutInference.js
+++ b/toolkit/components/aboutinference/content/aboutInference.js
@@ -79,6 +79,16 @@ let engineParent = null;
  * Presets for the pad
  */
 const INFERENCE_PAD_PRESETS = {
+  "paul": {
+    inputArgs: ["Sarah lives in the United States of America"],
+    runOptions: {},
+    task: "text-classification",
+    modelId: "Mozilla/tinybert-uncased-autofill",
+    modelRevision: "main",
+    modelHub: "huggingface",
+    dtype: "q8",
+    device: "wasm",
+  },
   "image-to-text": {
     inputArgs: [
       "https://huggingface.co/datasets/mishig/sample_images/resolve/main/football-match.jpg",
@@ -824,7 +834,7 @@ var selectedPreset;

 function fillSelect(elementId, values) {
   const selectElement = document.getElementById(elementId);
-  values.forEach(function (task) {
+  values.forEach(function(task) {
     const option = document.createElement("option");
     option.value = task;
     option.text = task;
@@ -860,7 +870,7 @@ async function getEngineParent() {
  *
  * @async
  */
-window.onload = async function () {
+window.onload = async function() {
   let menu = document.getElementById("categories");
   menu.addEventListener("click", function click(e) {
     if (e.target && e.target.parentNode == menu) {
@@ -875,18 +885,18 @@ window.onload = async function () {
   fillSelect("numThreads", getNumThreadsArray());
   fillSelect("predefined", PREDEFINED);

-  document.getElementById("predefined").value = "summary";
-  loadExample("summary");
+  document.getElementById("predefined").value = "paul";
+  loadExample("paul");
   document.getElementById("console").value = "";

   document
     .getElementById("inferenceButton")
     .addEventListener("click", runInference);
-  document.getElementById("modelHub").addEventListener("change", function () {
+  document.getElementById("modelHub").addEventListener("change", function() {
     var selectedOption = this.options[this.selectedIndex];
     selectedHub = selectedOption.value;
   });
-  document.getElementById("predefined").addEventListener("change", function () {
+  document.getElementById("predefined").addEventListener("change", function() {
     var selectedOption = this.options[this.selectedIndex];
     selectedPreset = selectedOption.value;
     loadExample(selectedPreset);
diff --git a/toolkit/components/ml/vendor/transformers-dev.js b/toolkit/components/ml/vendor/transformers-dev.js
index 1dcb65a041876..31f0483b7b699 100644
--- a/toolkit/components/ml/vendor/transformers-dev.js
+++ b/toolkit/components/ml/vendor/transformers-dev.js
@@ -34353,6 +34353,7 @@ class Tensor {
      * @param {[DataType, DataArray, number[]]|[ONNXTensor]} args
      */
     constructor(...args) {
+        debugger;
         if ((0,_backends_onnx_js__WEBPACK_IMPORTED_MODULE_1__.isONNXTensor)(args[0])) {
             this.ort_tensor = /** @type {ONNXTensor} */ (args[0]);
         } else {
(END)

open the browser toolbox and visit about:inference and run it

when the dev tools tries to display the data, it throws an error (that blocks execution of the main code)

TypeError: BigInt value can't be serialized in JSON
    Tensor chrome://global/content/ml/transformers-dev.js:34356
    _call chrome://global/content/ml/transformers-dev.js:28243
    closure chrome://global/content/ml/transformers-dev.js:31537
    _call chrome://global/content/ml/transformers-dev.js:22086
    closure chrome://global/content/ml/transformers-dev.js:31537
    run chrome://global/content/ml/backends/ONNXPipeline.mjs:657
    run chrome://global/content/ml/MLEngine.worker.mjs:99
    dispatch chrome://global/content/ml/MLEngine.worker.mjs:117
    handleMessage resource://gre/modules/workers/PromiseWorker.mjs:177
    connectToPromiseWorker chrome://global/content/ml/MLEngine.worker.mjs:125
    #connectToPromiseWorker chrome://global/content/ml/MLEngine.worker.mjs:125
    MLEngineWorker chrome://global/content/ml/MLEngine.worker.mjs:25
    <anonymous> chrome://global/content/ml/MLEngine.worker.mjs:132
event-emitter.js:257:19
    _emit resource://devtools/shared/event-emitter.js:257
    emit resource://devtools/shared/event-emitter.js:186
    emit resource://devtools/shared/event-emitter.js:330
    _pauseAndRespond resource://devtools/server/actors/thread.js:970
    onDebuggerStatement resource://devtools/server/actors/thread.js:1967
    Tensor chrome://global/content/ml/transformers-dev.js:34356
    _call chrome://global/content/ml/transformers-dev.js:28243
    closure chrome://global/content/ml/transformers-dev.js:31537
    _call chrome://global/content/ml/transformers-dev.js:22086
    closure chrome://global/content/ml/transformers-dev.js:31537
    run chrome://global/content/ml/backends/ONNXPipeline.mjs:657
    run chrome://global/content/ml/MLEngine.worker.mjs:99
    dispatch chrome://global/content/ml/MLEngine.worker.mjs:117
    handleMessage resource://gre/modules/workers/PromiseWorker.mjs:177
    connectToPromiseWorker chrome://global/content/ml/MLEngine.worker.mjs:125
    (Async: EventListener.handleEvent)
    #connectToPromiseWorker chrome://global/content/ml/MLEngine.worker.mjs:125
    MLEngineWorker chrome://global/content/ml/MLEngine.worker.mjs:25
    <anonymous> chrome://global/content/ml/MLEngine.worker.mjs:132

I was having a slightly different stacktrace in the terminal:

console.error: (new TypeError("BigInt value can't be serialized in JSON", "resource://devtools/shared/transport/worker-transport.js", 88))
TypeError: BigInt value can't be serialized in JSON: send@resource://devtools/shared/transport/worker-transport.js:88:12
send@resource://devtools/server/devtools-server-connection.js:88:20
_sendEvent@resource://devtools/shared/protocol/Actor.js:73:15
Actor/<@resource://devtools/shared/protocol/Actor.js:47:16
_emit@resource://devtools/shared/event-emitter.js:242:32
emit@resource://devtools/shared/event-emitter.js:186:18
emit@resource://devtools/shared/event-emitter.js:330:18
_pauseAndRespond@resource://devtools/server/actors/thread.js:970:12
onDebuggerStatement@resource://devtools/server/actors/thread.js:1967:17
Tensor@chrome://global/content/ml/transformers-dev.js:34356:9
_call@chrome://global/content/ml/transformers-dev.js:28243:31
closure@chrome://global/content/ml/transformers-dev.js:31537:28
_call@chrome://global/content/ml/transformers-dev.js:22086:35
closure@chrome://global/content/ml/transformers-dev.js:31537:28
run@chrome://global/content/ml/backends/ONNXPipeline.mjs:657:53
async*run@chrome://global/content/ml/MLEngine.worker.mjs:99:33
#connectToPromiseWorker/worker.dispatch@chrome://global/content/ml/MLEngine.worker.mjs:117:26
handleMessage@resource://gre/modules/workers/PromiseWorker.mjs:177:27
#connectToPromiseWorker/<@chrome://global/content/ml/MLEngine.worker.mjs:125:52
EventListener.handleEvent*#connectToPromiseWorker@chrome://global/content/ml/MLEngine.worker.mjs:125:10
MLEngineWorker@chrome://global/content/ml/MLEngine.worker.mjs:25:33
@chrome://global/content/ml/MLEngine.worker.mjs:132:1

which does point in a place where we call JSON.stringify, and the issue is that packets would have a frame with arguments containing "raw" BigInts, e.g. :

{
  "type": "message",
  "id": "server1.conn0.watcher2.process7//workerTarget23",
  "message": {
    "type": "paused",
    "actor": "server1.conn0.watcher2.process7//workerTarget23/pause18",
    "frame": {
      "actor": "server1.conn0.watcher2.process7//workerTarget23/frame19",
      "type": "call",
      "asyncCause": null,
      "state": "on-stack",
      "this": {
        "type": "object",
        "actor": "server1.conn0.watcher2.process7//workerTarget23/obj20",
        "class": "Object",
        "ownPropertyLength": 1,
        "extensible": true,
        "frozen": false,
        "sealed": false,
        "isError": false,
        "preview": {
          "kind": "Object",
          "ownProperties": {
            "ort_tensor": {
              "configurable": true,
              "enumerable": true,
              "writable": true,
              "value": {
                "type": "undefined"
              }
            }
          },
          "ownPropertiesLength": 1
        }
      },
      "displayName": "Tensor",
      "arguments": [
        {
          "type": "object",
          "actor": "server1.conn0.watcher2.process7//workerTarget23/obj21",
          "class": "Array",
          "ownPropertyLength": 4,
          "extensible": true,
          "frozen": false,
          "sealed": false,
          "isError": false,
          "preview": {
            "kind": "ArrayLike",
            "length": 3,
            "items": [
              "int64",
              {
                "type": "object",
                "actor": "server1.conn0.watcher2.process7//workerTarget23/obj22",
                "class": "BigInt64Array",
                "ownPropertyLength": 10,
                "extensible": true,
                "frozen": false,
                "sealed": false,
                "isError": false,
                "preview": {
                  "kind": "ArrayLike",
                  "length": 10
                }
              },
              {
                "type": "object",
                "actor": "server1.conn0.watcher2.process7//workerTarget23/obj23",
                "class": "Array",
                "ownPropertyLength": 3,
                "extensible": true,
                "frozen": false,
                "sealed": false,
                "isError": false,
                "preview": {
                  "kind": "ArrayLike",
                  "length": 2
                }
              }
            ]
          }
        },
        {
          "type": "object",
          "actor": "server1.conn0.watcher2.process7//workerTarget23/obj22",
          "class": "BigInt64Array",
          "ownPropertyLength": 10,
          "extensible": true,
          "frozen": false,
          "sealed": false,
          "isError": false,
          "preview": {
            "kind": "ArrayLike",
            "length": 10,
            "items": [
              "101n",
              "4532n",
              "3268n",
              "1999n",
              "1996n",
              "2142n",
              "2163n",
              "1997n",
              "2637n",
              "102n"
            ]
          }
        },
        {
          "type": "object",
          "actor": "server1.conn0.watcher2.process7//workerTarget23/obj23",
          "class": "Array",
          "ownPropertyLength": 3,
          "extensible": true,
          "frozen": false,
          "sealed": false,
          "isError": false,
          "preview": {
            "kind": "ArrayLike",
            "length": 2,
            "items": [
              1,
              10
            ]
          }
        }
      ],
      "where": {
        "actor": "server1.conn0.watcher2.process7//workerTarget23/source12",
        "line": 34356,
        "column": 8
      }
    },
    "why": {
      "type": "debuggerStatement"
    },
    "from": "server1.conn0.watcher2.process7//workerTarget23/thread1"
  }
}

I'm checking if this can be reproduced without a worker

Smaller STR:

  • Open attachment
  • Open Debugger
  • Click on the button in the page

ER: Should pause in the worker
AR: Doesn't pause

Oh, thanks a lot for the easily reproducible report!

It is only about BigInt64Array and nothing is specific to workers.

Simple STR with regular debugger and no worker:

  • Open the debugger and navigate to data:text/html,<script>const array = new BigInt64Array(1); array[0] = BigInt(42); debugger</script>
  • It should pause the page, but the debugger UI won't tell you that because of the following exception:
TypeError: BigInt value can't be serialized in JSON
Stack: send/<@resource://devtools/shared/transport/local-transport.js:69:22
Assignee: nobody → nchevobbe
Status: NEW → ASSIGNED

(In reply to Alexandre Poirot [:ochameau] from comment #3)

Oh, thanks a lot for the easily reproducible report!

It is only about BigInt64Array and nothing is specific to workers.

Simple STR with regular debugger and no worker:

  • Open the debugger and navigate to data:text/html,<script>const array = new BigInt64Array(1); array[0] = BigInt(42); debugger</script>
  • It should pause the page, but the debugger UI won't tell you that because of the following exception:
TypeError: BigInt value can't be serialized in JSON
Stack: send/<@resource://devtools/shared/transport/local-transport.js:69:22

I'm pausing just fine in the toolbox debugger with this page. Were you seeing this in the Browser Toolbox or doing remote debugging?

Flags: needinfo?(poirot.alex)

This allows to properly serialize arrays with non-serializable items (e.g. BigInt64Array).
Tests cases are added to check that we get a proper packet for those, as well as making
sure we're not hitting the bug in the debugger that is described in the bug.
We also make sure those objects are properly rendered in the console output.
For that, we create a generic test for checking previews, based on browser_webconsole_trusted_types.js,
so it's easier to add such test case in the future (we might also use this test for
migrating away from our jest tests).

(In reply to Nicolas Chevobbe [:nchevobbe] from comment #4)

(In reply to Alexandre Poirot [:ochameau] from comment #3)

Oh, thanks a lot for the easily reproducible report!

It is only about BigInt64Array and nothing is specific to workers.

Simple STR with regular debugger and no worker:

  • Open the debugger and navigate to data:text/html,<script>const array = new BigInt64Array(1); array[0] = BigInt(42); debugger</script>
  • It should pause the page, but the debugger UI won't tell you that because of the following exception:
TypeError: BigInt value can't be serialized in JSON
Stack: send/<@resource://devtools/shared/transport/local-transport.js:69:22

I'm pausing just fine in the toolbox debugger with this page. Were you seeing this in the Browser Toolbox or doing remote debugging?

Oh yes, you are right. I must have been confused with a browser toolbox in background...
I confirm it works finaly locally.
Structured cloning works fine with such type and explains why it only fails in remote/workers.
The following code doesn't throw:
let array = new BigInt64Array(1); array[0]=BigInt(1); new StructuredCloneHolder("foo", null, array).deserialize(globalThis)

Flags: needinfo?(poirot.alex)
See Also: → 1956441

(In reply to Alexandre Poirot [:ochameau] from comment #6)

Structured cloning works fine with such type and explains why it only fails in remote/workers.
The following code doesn't throw:
let array = new BigInt64Array(1); array[0]=BigInt(1); new StructuredCloneHolder("foo", null, array).deserialize(globalThis)

I filed Bug 1956441 to see if we can switch the worker transport to structured clone.

Severity: -- → S3
Priority: -- → P2
Pushed by nchevobbe@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/f0268a9cb2ff [devtools] Create grips for items in typed arrays. r=devtools-reviewers,ochameau.
Status: ASSIGNED → RESOLVED
Closed: 1 year ago
Resolution: --- → FIXED
Target Milestone: --- → 138 Branch
Regressions: 1959948
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: