🏠 back to Observable

How to get normal stack traces from libraries?

Spawned from "global is undefined" when using viz.js through d3-graphviz

Is it possible to get a complete stack trace from errors in libraries instead of just the error message without any references to where the error occurs?

Complete stack traces are shown in your browser’s developer console, and you can use you browser’s debugger to step into code, too (e.g., by putting a debugger statement in a cell, opening the developer console, and then hitting Shift-Enter to run the cell).

What I meant was that I don’t get stack traces in the browser’s developer console, just an error message in the notebook. Try https://beta.observablehq.com/@magjac/d3-graphviz-fiddling-not-working (it’s in the trash, but runs anyway).

The console says:

Content Security Policy: Couldn’t process unknown directive ‘prefetch-src’
TypeError: asm.js type error: incompatible type for argument 5: (i32 here vs. f64 before)
viz.js:37:88925
Event 1 start 2 0
d3-graphviz.min.js:1:23274
Event 2 layoutStart 4 4
d3-graphviz.min.js:1:23274
TypeError: asm.js type error: incompatible type for argument 5: (i32 here vs. f64 before)
viz:34:228942

(Sorry for the poor formatting)

The global is undefined error message in the notebook is not seen in the console, neither is any stack trace.

I’m using Firefox 59.0.2 (64-bit) on Ubuntu 16.04.3

In Chrome Version 64.0.3282.167 (Official Build) (64-bit) it’s the same thing, but the error message is different: Cannot read property ‘Int8Array’ of undefined

I’m assuming that Observable catches the error and shows the error message in the notebook, instead of letting the browser dump a stack trace. I was hoping there was a way to turn this off.

We can’t view notebooks in your trash, so I can’t reproduce the error, sorry. Are you referring to an error that occurs during require? The current behavior of d3-require (which is our implementation of require) is that errors on load are caught and rethrown as an “invalid module” error. Unfortunately this means that you won’t see the original stack trace of the error in the console, but you can still use the debugger to debug the exception that is thrown.

I’ve brought it back from the trash.

No, it occurs (I think) when d3-graphviz calls Viz. See the description in "global is undefined" when using viz.js through d3-graphviz

No exception is thrown.

If you pop open your debugger, you will see that the stack trace is being swallowed by d3-graphviz:

Because it says throw error.message rather than throw error, the stack trace is lost. I’m not sure what’s causing the actual error inside of Viz.js, though… it seems like somehow Module.asmGlobalArg is undefined, but it’s hard to debug because it’s all code generated by emscripten.

I’m not seeing what you are seeing:

With “Pause on caught exceptions” ticked I get:

I can see you’re getting the unminified version, while I’m getting the minified:

How did you go about to end up where you did? Did you change something in the notebook or some settings in the debugger?

You have to step through about 30 spurious uncaught exceptions before you get to the “real” exception, due to an unfortunate consequence of Viz.js being transpiled by emscripten.

(The particular error you screenshotted is actually in your ad blocker! Google analytics, but most of those errors appear to be Viz.js trying to create temporary files in a file system, which of course isn’t possible in a browser, but I’m not sure why the code does this.)

I made two other changes: I clicked the {} in the developer tools to get Chrome to pretty-print the code, which is practically essential to see where the error is occurring, especially with minified or transpiled code; and I switched to the non-minified version so that it was easier to see what was happening.

That said, I think Chrome’s debugger isn’t able to debug large amounts of asm code, because it seemed to crash and give inconsistent behavior. It’s possible that this is a bug in Chrome, although I can’t explain why Viz.js-lite seems to work fine by itself.

How did you switch to the non-minified version?

I edited the cell that said

d3_graphviz = require("https://unpkg.com/d3-graphviz@2.0.0/build/d3-graphviz.min.js")

To instead say

d3_graphviz = require("https://unpkg.com/d3-graphviz@2.0.0/build/d3-graphviz.js")

Doh! I thought I was already doing that :flushed:

1 Like

Sorry for the delay. I was banned to reply for 7 hours because it was my first day at the forum.

After patient stepping and typing “throw error”, I get the same screenshot as you:

I still don’t understand why I don’t get that error message in the console without manually typing “throw error”. I would have expected to see this anyway (possibly without the stack trace).

Do you mean that by changing the code to “throw error” instead of “throw error.message”, I would get that? I doubt it, but I will try it although right now How to load experimental versions of libraries? is hampering me.

I still think that Observable is catching the error somehow. How else would it be able to show the error in the notebook itself?

Yes, Observable catches the error so that it can display the message in the cell in which it occurs, and to highlight the location of the error by applying a sourcemap to translate the error location in the generated code back to its original location in the cell’s source.

We don’t log errors thrown by cells to the console because in the normal case you are debugging code in cells, which is transpiled and eval’d, so a native stack trace wouldn’t be especially helpful compared to our cell-level error highlighting. This case is unusual because we are debugging code in a third-party library rather than the notebook, so the source isn’t visible on the page. Using the browser’s built-in debugger is the recommended approach for debugging code outside of your notebook.

Thanks. So back to my original question. Is it possible turn off this behavior?

I don’t think the stack traces are logged any more? At least it doesn’t seem to work for me (tested with Chrome Safari Firefox on https://observablehq.com/d/065fdeb6e6255e39 ) : no trace of a stack trace in the console.

2 Likes

I think you have to select “Pause on exceptions” in your dev tools

Merci, it works on Firefox. I haven’t found a solution on Chrome though (I found the “pause on exceptions” button in the “Sources” panel, but it doesn’t log a stack trace on my test notebook).

I’m not sure how to reconcile Mike’s messages, and my observations:

Complete stack traces are shown in your browser’s developer console

and

Observable catches the error so that it can display the message in the cell in which it occurs

There are two issues at play here:

  1. In order to pause errors that have already been caught by Observable (which is all errors) you also need to check “Pause on caught exceptions”.
  2. Unfortunately Observable catches a lot of errors behind the scenes. Most notable are parsing errors that will pop up whenever you move the mouse over a cell or switch focus back to the page. It can be incredibly frustrating to navigate past these errors in order to trigger the one error you actually want to inspect.
    Chrome has no shortcuts to trigger pausing on exceptions or switching focus between the dev tools and the viewport. The least painful method I’ve found to initiate an error without triggering too many of Observable’s internal ones is:
    1. Have the dev tools open in a floating (undocked) window.
    2. In your main viewport, focus the element you want to control (e.g. a cell that you want to run).
    3. In your dev tools, enable pausing on exceptions (including caught exceptions).
    4. Focus back to your page via cmd+shift+"<" (or by clicking on the tab outside the viewport).
    5. Click “play” in your dev tools window for approx. two caught errors that will appear.
    6. Your main window should still have its focus. You can now interact with it, preferably via keyboard.

In my opinion the overall debugging experience in Observable (at least in Chrome) has gotten worse in the past months.

2 Likes

A while back I created some helper functions to produce stack traces, with varying success:

When you go on a hunt for errors you’ll want to use named functions whereever possible, as only these will make your traces at least partially readable.