# \`rethrow\` operator

**URL:** <https://es.discourse.group/t/rethrow-operator/1406>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [July 25, 2022, 7:53am UTC](https://es.discourse.group/t/rethrow-operator/1406 "2022-07-25T07:53:02Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [July 25, 2022, 7:53am UTC](https://es.discourse.group/t/rethrow-operator/1406/1 "2022-07-25T07:53:02Z")

</div>

The idea is simple: a `rethrow` key word to use inside `catch` blocks. This would cause errors that are re-thrown to be thrown as if from their original location, so as to not disrupt the error stack.

For example:

```javascript
try {
  // ...
} catch (e) {
  if (!(e instanceof SomeSpecificError)) rethrow e // make it behave as it would have normally

  // ... handle special error ...
}

```

The idea is that the error would behave _exactly_ as if it was thrown from its original location before `try` catch would have intercepted it, as if there never were a try catch.

Currently, when we re-throw errors using `throw`, the stack trace that dev tools shows will not be exactly as where the error originated, but will include the new `throw` location (can be confusing).

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 25, 2022, 8:47am UTC](https://es.discourse.group/t/rethrow-operator/1406/2 "2022-07-25T08:47:19Z")

</div>

That’s not correct; stack traces are fixed when an error is created; re throwing it has no effect. If it does, file a bug on that browser.

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [July 25, 2022, 12:57pm UTC](https://es.discourse.group/t/rethrow-operator/1406/3 "2022-07-25T12:57:03Z")

</div>

@ljharb the developer tools can only pause where an error is thrown (throw expr), not where the Error instance has been created (new Error)

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [July 25, 2022, 2:24pm UTC](https://es.discourse.group/t/rethrow-operator/1406/4 "2022-07-25T14:24:08Z")

</div>

@JackWorks the developer tools can however pause both in the location where it is thrown the first time (if _break on caught exceptions_ is enabled) and in the location where it is re-thrown (if _break on exceptions_ is enabled).

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 25, 2022, 10:28pm UTC](https://es.discourse.group/t/rethrow-operator/1406/5 "2022-07-25T22:28:13Z")

</div>

Dev tools can choose whatever behavior they like; regardless, a _stack trace_ (which is what the OP described) is never generated from throwing - only from creating a new error object.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [July 25, 2022, 10:50pm UTC](https://es.discourse.group/t/rethrow-operator/1406/6 "2022-07-25T22:50:02Z")

</div>

I suppose it is the devtools behavior that is not ideal. Maybe the spec can address that; that's what the `rethrow` idea was for. I do see that if I inspect the `error.stack` I see the original stack. But devtools shows me other stuff based on where an error is re-thrown.

Essentially what I was hoping for is a way to cause the try-catch to behave as if it was never there.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 26, 2022, 3:08am UTC](https://es.discourse.group/t/rethrow-operator/1406/7 "2022-07-26T03:08:27Z")

</div>

Who's dev-tools are we talking about here?

I tried using the following code sample:

```javascript
function fn1() {
  try {
    fn2();
  } catch (err) {
    throw err;
  }
}
function fn2() {
  throw new Error('Whoops!');
}
fn1();

```

In Chrome's REPL, I get the correct stack trace

![image](https://global.discourse-cdn.com/free1/uploads/es/original/2X/b/b3cc68916db01fbb71b3b7c5d3d0ad95809eca73.png)

Firefox's REPL works as well:  
 ![image](https://global.discourse-cdn.com/free1/uploads/es/original/2X/6/6c223cc266d8f5660fe4421ec81bc2f3e5cfe4f6.png)

Here's Node's

```javascript
Uncaught Error: Whoops!
    at fn2 (REPL10:2:9)
    at fn1 (REPL7:3:5)

```

If I'm using breakpoints in Chrome, I still get the correct callstack in its debugger if I make sure to ask it to "Pause on caught exceptions".

![image](https://global.discourse-cdn.com/free1/uploads/es/original/2X/b/be5de73e1b0d740aa62bc7cfaf3e77aabd5d9227.png)

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [July 26, 2022, 5:39am UTC](https://es.discourse.group/t/rethrow-operator/1406/8 "2022-07-26T05:39:38Z")

</div>

Hmmm, you're right, nvm, not sure what I saw. Was it always like that? Maybe an async stack threw me off; but that only adds to the stack when expanded, it looks like.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 26, 2022, 5:50am UTC](https://es.discourse.group/t/rethrow-operator/1406/9 "2022-07-26T05:50:39Z")

</div>

Yea, it’s always been like that afaik.

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [August 14, 2022, 8:41am UTC](https://es.discourse.group/t/rethrow-operator/1406/10 "2022-08-14T08:41:09Z")

</div>

Didn't Edge (pre-Chromium) and old Safari initially set it on `throw`? I do recall a long time ago running into that with PhantomJS where I was getting `undefined` before `throw` and a string after. Doesn't reproduce on current iOS Safari, though.

May be worth checking behavior in various engines, especially outside the main ones (V8, JavaScriptCore, SpiderMonkey, and ChakraCore), to verify what everyone does.

---

<div class="post-metadata">

**Author:** ![pygy](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/pygy/32/231_2.png) [@pygy](https://es.discourse.group/u/pygy)\
**Post date:** [August 15, 2022, 12:08am UTC](https://es.discourse.group/t/rethrow-operator/1406/11 "2022-08-15T00:08:41Z")

</div>

IE up to v11 needs a `throw` statement to attach a stack trace (we still have a [code path to handle that scenario](https://github.com/MithrilJS/ospec/blob/6379ceba5e2b1d6aefa5568d60cc30287f8b9347/ospec.js#L57-L61) in `ospec`). No idea for Edge and Safari.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [August 15, 2022, 4:14am UTC](https://es.discourse.group/t/rethrow-operator/1406/12 "2022-08-15T04:14:28Z")

</div>

I ran into the issue, I knew I was seeing something funky. I just didn't know how to reproduce it, but now I can any time by making Solid.js re-throw any error.

The call stack is async.

This is what I see when I pause on the line that re-throws the error:

 ![error_rethrown_in_solid](https://global.discourse-cdn.com/free1/uploads/es/original/2X/a/a0d8e760a8e0f787815bdc38eab2946b6dd6539f.png)

This is what I see in the console:

 ![closed-error](https://global.discourse-cdn.com/free1/uploads/es/original/2X/8/8959fd8f37b9fcc62a2489f8a30cc0abad76528a.png)

Opening the first dropdown shows this:

 ![error-first-dropdown](https://global.discourse-cdn.com/free1/uploads/es/original/2X/1/1eceb0f365a6909f331e572f23a0d40783e0725d.png)

Opening the second drop down shows the original error unformatted:

 ![error-second-dropdown](https://global.discourse-cdn.com/free1/uploads/es/original/2X/a/ae672855cf9c4a4cd92d344113ce4d26da4bf33b.png)

The `handleError` function is in a try-catch block like this:

```javascript
  try {
    nextValue = node.fn(value);
  } catch (err) {
    handleError(err);
  }

```

As you can tell by these screenshots, Chrome is showing the trace for the location where the `throw` happens, not the trace for the re-thrown error.

* * *

EDIT: Oh, hmm. Maybe it has to do with the `DeveloperError` being defined like this:

```javascript
function DeveloperError(message) {
  this.name = "DeveloperError";
  this.message = message;

  //Browsers such as IE don't have a stack property until you actually throw the error.
  let stack;
  try {
    throw new Error();
  } catch (e) {
    stack = e.stack;
  }

  this.stack = stack;
}

if (defined(Object.create)) {
  DeveloperError.prototype = Object.create(Error.prototype);
  DeveloperError.prototype.constructor = DeveloperError;
}

DeveloperError.prototype.toString = function () {
  let str = `${this.name}: ${this.message}`;

  if (defined(this.stack)) {
    str += `\n${this.stack.toString()}`;
  }

  return str;
};

```
