# Error Reporting

**URL:** <https://talk.observablehq.com/t/error-reporting/3771>\
**Category:** Help\
**Created:** [August 26, 2020, 8:39am UTC](https://talk.observablehq.com/t/error-reporting/3771 "2020-08-26T08:39:52Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![GordonSmith](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/gordonsmith/32/6902_2.png) [@GordonSmith](https://talk.observablehq.com/u/GordonSmith)\
**Post date:** [August 26, 2020, 8:39am UTC](https://talk.observablehq.com/t/error-reporting/3771/1 "2020-08-26T08:39:52Z")

</div>

Is there any way (throwing a special exception?) to report a runtime error, so it shows up red with a marker like an Observable syntax does?

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [August 26, 2020, 9:04am UTC](https://talk.observablehq.com/t/error-reporting/3771/2 "2020-08-26T09:04:17Z")

</div>

Doesn’t `throw Error("my error")` work for you?

---

<div class="post-metadata">

**Author:** ![GordonSmith](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/gordonsmith/32/6902_2.png) [@GordonSmith](https://talk.observablehq.com/u/GordonSmith)\
**Post date:** [August 26, 2020, 9:57am UTC](https://talk.observablehq.com/t/error-reporting/3771/3 "2020-08-26T09:57:26Z")

</div>

Unfortunately no - probably due to where its getting thrown?:

```auto
function layout(layout) {
  function * _(parts, ...args) {
    const div = html`<div>...loading...</div>`;
    yield div;

    const str = parts.map((s, i) => s + (i < args.length ? args[i] : "")).join("");

    graphviz.layout(str, "svg", layout).then(html=>{
      div.innerHTML = html;
    }).catch(e=>{
      div.innerText = e.message;
      throw e;
    });
  }
  return _;
}

```

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [August 26, 2020, 2:36pm UTC](https://talk.observablehq.com/t/error-reporting/3771/4 "2020-08-26T14:36:09Z")

</div>

Does it work if you change

```auto
throw e;

```

to

```auto
throw Error(e.message);

```

?

~~I suspect that Observable relies on the `fileName` and `lineNumber` properties~~ Observable relies on the [`stack`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack) property of an `Error` object to mark the error source. E.g., tracking won’t work either if you simply throw a string.

---

<div class="post-metadata">

**Author:** ![GordonSmith](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/gordonsmith/32/6902_2.png) [@GordonSmith](https://talk.observablehq.com/u/GordonSmith)\
**Post date:** [August 26, 2020, 3:11pm UTC](https://talk.observablehq.com/t/error-reporting/3771/5 "2020-08-26T15:11:32Z")

</div>

Afraid not, tried all the obvious ones:

- throw e
- throw Error(“Hello”);
- throw new Error(“Hello”);

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [August 26, 2020, 4:04pm UTC](https://talk.observablehq.com/t/error-reporting/3771/6 "2020-08-26T16:04:36Z")

</div>

You need to return the error object. So in your generator you’ll have to yield the `graphviz.layout` promise. Check out this example:

```auto
function* errorView() {
  let resolve, reject;
  const p = new Promise((res, rej) => {
          resolve = res, reject = rej;
        }),
        timer = Promises.delay(5000).then(() => {
          throw Error('time\'s up!');
        }),
        yep = Object.assign(html`<button>Resolve`, {
          onclick() { resolve('Done!') }
        }),
        nope = Object.assign(html`<button>Reject`, {
         onclick() { reject(Error('Not gonna happen')) }
        });
  
  yield html`<div>Stand by, we're "loading" (5sec max). ${yep} ${nope}`;
  yield Promise.race([p, timer]).then(data => html`<div>${data}`)
}

```

```auto
errorView()

```

---

<div class="post-metadata">

**Author:** ![GordonSmith](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/gordonsmith/32/6902_2.png) [@GordonSmith](https://talk.observablehq.com/u/GordonSmith)\
**Post date:** [August 27, 2020, 5:49am UTC](https://talk.observablehq.com/t/error-reporting/3771/7 "2020-08-27T05:49:27Z")

</div>

The main difference between your code and what I had, was that you end up returning two DOM Elements (one for the “loading” and one for the “Graphic”).

Where in my code it only returned the 1 DOM Element and updated it when the promise resolved.

In practice I suspect its not really an issue…

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [August 27, 2020, 7:23am UTC](https://talk.observablehq.com/t/error-reporting/3771/8 "2020-08-27T07:23:17Z")

</div>

> [@GordonSmith](#):
>
> In practice I suspect its not really an issue…

Yes, I skipped the additional variable to keep the example more concise.

Out of interest: Is there a benefit to returning a generator function from layout(), as opposed to changing the signature to `function* layout(layout, parts, ...args)`? Or is that snippet stripped down?

---

<div class="post-metadata">

**Author:** ![GordonSmith](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/gordonsmith/32/6902_2.png) [@GordonSmith](https://talk.observablehq.com/u/GordonSmith)\
**Post date:** [August 27, 2020, 9:30am UTC](https://talk.observablehq.com/t/error-reporting/3771/9 "2020-08-27T09:30:15Z")

</div>

Just to save cut / paste code.

FWIW the “simple” working code looks like this (no loading message):

```auto
function layout(layout) {
  return function (parts, ...args) {
    const str = parts.map((s, i) => s + (i < args.length ? args[i] : "")).join("");
    
    return graphviz.layout(str, "svg", layout).then(svg => {
      return html`<div>${svg}</div>`;
    });
  }
}

```

The “complex” working code looks like this (but creates a new div when svg is resolved):

```auto
function layout(layout) {
  return function * (parts, ...args) {
    yield html`<div>...loading...</div>`;
    
    const str = parts.map((s, i) => s + (i < args.length ? args[i] : "")).join("");
    
    yield graphviz.layout(str, "svg", layout).then(svg => {
      return html`<div>${svg}</div>`
    });
  }
}

```

Finally this is closer to what I was shooting for, but the “jump to error” is in the wrong place!

```auto
function layout(layout) {
  return async function * (parts, ...args) {
    const div = html`<div>...loading...</div>`;
    yield div;
    
    const str = parts.map((s, i) => s + (i < args.length ? args[i] : "")).join("");
    
    const err = await graphviz.layout(str, "svg", layout).then(svg => {
      div.innerHTML = svg;
    });
    
    if (err !== undefined) {
       yield err;
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [August 27, 2020, 11:54am UTC](https://talk.observablehq.com/t/error-reporting/3771/10 "2020-08-27T11:54:06Z")

</div>

> [@GordonSmith](#):
>
> Finally this is closer to what I was shooting for, but the “jump to error” is in the wrong place!

That’s because the `Error` object’s stack only contains this:

```plaintext
Error: syntax error in line 16 near '-'

    at https://cdn.jsdelivr.net/npm/@hpcc-js/wasm@0.3.14/dist/index.min.js:1:114161

```

As you can see, `layout()` is nowhere in that stack. If you want “Jump to error” to point to `layout()`, you’ll have to throw a new error:

```auto
.catch(e => { throw Error(e) })`

```

… Or did I misunderstand what you meant by “wrong place”?
