Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MISC: Add error cause to exceptionAlert and Recovery mode #1772

Conversation

catloversg
Copy link
Contributor

Let's check this code:

function throw1() {
  throw new Error("throw1");
}

function throw2() {
  throw new Error("throw2");
}

function test() {
  try {
    if (Date.now() % 2 === 0) {
      throw1();
    } else {
      throw2();
    }
  } catch (e) {
    throw new Error("test", { cause: e });
  }
}

/** @param {NS} ns */
export async function main(ns) {
  console.clear();
  try {
    test();
  } catch (e) {
    console.log(String(e));
    console.log(String(e.stack));
    console.log(String(e.cause.stack));
  }
}

Example output:

Error: test
Error: test
    at test (a.js:17:11)
    at main (a.js:25:5)
    at startNetscript2Script (NetscriptWorker.ts:87:9)
Error: throw1
    at throw1 (a.js:2:9)
    at test (a.js:12:7)
    at main (a.js:25:5)
    at startNetscript2Script (NetscriptWorker.ts:87:9)
Error: test
Error: test
    at test (a.js:17:11)
    at main (a.js:25:5)
    at startNetscript2Script (NetscriptWorker.ts:87:9)
Error: throw2
    at throw2 (a.js:6:9)
    at test (a.js:14:7)
    at main (a.js:25:5)
    at startNetscript2Script (NetscriptWorker.ts:87:9)

Without e.cause, we cannot know the root cause (was the error thrown by throw1 or throw2?). This PR adds the error.cause to relevant error reporting UI.

Screenshots:
Capture1
Capture2

@d0sboots
Copy link
Collaborator

Before you decide on this, test the result of error.toString(), which IIRC is different than String(error). You'll also want to look at the results on both Chrome and Firefox, since they have distinctly different error logging.

@catloversg
Copy link
Contributor Author

catloversg commented Nov 12, 2024

Test code:

/** @param {NS} ns */
export async function main(ns) {
  ns.clearLog();
  const error1 = new Error("error1");
  const error2 = new Error("error2", { cause: error1 });
  const error3 = "error3";
  ns.print(`error1: String constructor: ${String(error1)}`);
  ns.print(`error2: String constructor: ${String(error2)}`);
  ns.print(`error3: String constructor: ${String(error3)}`);
  ns.print(`error1: toString(): ${error1.toString()}`);
  ns.print(`error2: toString(): ${error2.toString()}`);
  ns.print(`error3: toString(): ${error3.toString()}`);
}

Chrome:

error1: String constructor: Error: error1
error2: String constructor: Error: error2
error3: String constructor: error3
error1: toString(): Error: error1
error2: toString(): Error: error2
error3: toString(): error3

Firefox:

error1: String constructor: Error: error1
error2: String constructor: Error: error2
error3: String constructor: error3
error1: toString(): Error: error1
error2: toString(): Error: error2
error3: toString(): error3

The difference between Chrome and Firefox shows up when we use stack and other non-standard properties (e.g., columnNumber, fileName, lineNumber).

/** @param {NS} ns */
export async function main(ns) {
  ns.clearLog();
  const error1 = new Error("error1");
  const error2 = new Error("error2", { cause: error1 });
  ns.print(`error1.stack: ${error1.stack}`);
  ns.print(`error2.stack: ${error2.stack}`);
}

Chrome:

error1.stack: Error: error1
    at main (home/a.js:4:18)
    at startNetscript2Script (webpack://bitburner/./src/NetscriptWorker.ts?:87:9)
error2.stack: Error: error2
    at main (home/a.js:5:18)
    at startNetscript2Script (webpack://bitburner/./src/NetscriptWorker.ts?:87:9)

Firefox:

error1.stack: main@home/a.js:4:18
startNetscript2Script@webpack://bitburner/./src/NetscriptWorker.ts?:87:9
async*createAndAddWorkerScript@webpack://bitburner/./src/NetscriptWorker.ts?:343:142
startWorkerScript@webpack://bitburner/./src/NetscriptWorker.ts?:297:31
run@webpack://bitburner/./src/ui/React/LogBoxManager.tsx?:225:74
callCallback@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3945:14
invokeGuardedCallbackDev@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3994:16
invokeGuardedCallback@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:4056:31
invokeGuardedCallbackAndCatchFirstError@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:4070:25
executeDispatch@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8243:42
processDispatchQueueItemsInOrder@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8275:22
processDispatchQueue@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8288:37
dispatchEventsForPlugins@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8299:23
dispatchEventForPluginEventSystem/<@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8508:12
batchedEventUpdates$1@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:22391:12
batchedEventUpdates@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3745:12
dispatchEventForPluginEventSystem@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8507:22
attemptToDispatchEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:6005:36
dispatchEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:5924:41
unstable_runWithPriority@webpack://bitburner/./node_modules/scheduler/cjs/scheduler.development.js?:468:12
runWithPriority$1@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:11276:10
discreteUpdates$1@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:22408:14
discreteUpdates@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3756:12
dispatchDiscreteEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:5889:18
EventListener.handleEvent*addEventBubbleListener@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:6011:10
addTrappedEventListener@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8411:29
listenToNativeEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8374:28
listenToAllSupportedEvents/<@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8326:28
listenToAllSupportedEvents@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8324:21
createRootImpl@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25882:31
ReactDOMBlockingRoot@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25830:24
createLegacyRoot@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25895:10
legacyCreateRootFromDOMContainer@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25976:10
legacyRenderSubtreeIntoContainer@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:26002:44
render@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:26098:10
@webpack://bitburner/./src/index.tsx?:18:40
./src/index.tsx@https://bitburner.local/legacy/dist/main.bundle.js:7167:1
__webpack_require__@https://bitburner.local/legacy/dist/main.bundle.js:9442:42
__webpack_exports__<@https://bitburner.local/legacy/dist/main.bundle.js:9789:108
__webpack_require__.O@https://bitburner.local/legacy/dist/main.bundle.js:9484:23
@https://bitburner.local/legacy/dist/main.bundle.js:9790:53
@https://bitburner.local/legacy/dist/main.bundle.js:9792:12
error2.stack: main@home/a.js:5:18
startNetscript2Script@webpack://bitburner/./src/NetscriptWorker.ts?:87:9
async*createAndAddWorkerScript@webpack://bitburner/./src/NetscriptWorker.ts?:343:142
startWorkerScript@webpack://bitburner/./src/NetscriptWorker.ts?:297:31
run@webpack://bitburner/./src/ui/React/LogBoxManager.tsx?:225:74
callCallback@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3945:14
invokeGuardedCallbackDev@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3994:16
invokeGuardedCallback@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:4056:31
invokeGuardedCallbackAndCatchFirstError@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:4070:25
executeDispatch@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8243:42
processDispatchQueueItemsInOrder@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8275:22
processDispatchQueue@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8288:37
dispatchEventsForPlugins@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8299:23
dispatchEventForPluginEventSystem/<@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8508:12
batchedEventUpdates$1@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:22391:12
batchedEventUpdates@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3745:12
dispatchEventForPluginEventSystem@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8507:22
attemptToDispatchEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:6005:36
dispatchEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:5924:41
unstable_runWithPriority@webpack://bitburner/./node_modules/scheduler/cjs/scheduler.development.js?:468:12
runWithPriority$1@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:11276:10
discreteUpdates$1@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:22408:14
discreteUpdates@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:3756:12
dispatchDiscreteEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:5889:18
EventListener.handleEvent*addEventBubbleListener@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:6011:10
addTrappedEventListener@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8411:29
listenToNativeEvent@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8374:28
listenToAllSupportedEvents/<@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8326:28
listenToAllSupportedEvents@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:8324:21
createRootImpl@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25882:31
ReactDOMBlockingRoot@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25830:24
createLegacyRoot@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25895:10
legacyCreateRootFromDOMContainer@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:25976:10
legacyRenderSubtreeIntoContainer@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:26002:44
render@webpack://bitburner/./node_modules/react-dom/cjs/react-dom.development.js?:26098:10
@webpack://bitburner/./src/index.tsx?:18:40
./src/index.tsx@https://bitburner.local/legacy/dist/main.bundle.js:7167:1
__webpack_require__@https://bitburner.local/legacy/dist/main.bundle.js:9442:42
__webpack_exports__<@https://bitburner.local/legacy/dist/main.bundle.js:9789:108
__webpack_require__.O@https://bitburner.local/legacy/dist/main.bundle.js:9484:23
@https://bitburner.local/legacy/dist/main.bundle.js:9790:53
@https://bitburner.local/legacy/dist/main.bundle.js:9792:12

Some non-standard properties are implemented by only Firefox (e.g., columnNumber, fileName, lineNumber).

Copy link
Collaborator

@d0sboots d0sboots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a complicated bit of code somewhere that attempts to parse and partially rewrite stack traces. It feels like this should potentially be unified with that, so we don't have so many different error handling functions bumping around.

src/utils/ErrorHelper.ts Outdated Show resolved Hide resolved
@d0sboots
Copy link
Collaborator

You get a nicely formatted error with both the message, stack, and cause, if you directly console. log an error, but I guess there's no simple and portable way to recreate that as a string. Pity.

@d0sboots
Copy link
Collaborator

I guess that other function turned out not to be relevant?

@d0sboots d0sboots merged commit 4f84a89 into bitburner-official:dev Nov 13, 2024
5 checks passed
@catloversg
Copy link
Contributor Author

I checked that code (errorMessage in src\Netscript\ErrorMessages.ts), but I don't think we should merge the new function parseUnknownError and related code with it. Those parts are used for different purposes:

  • parseUnknownError and related code: Although they are used to parse unknown errors, they mainly deal with an instance of Error. The main purpose is to parse the error string, stack, and cause from the "potential" error instance. They are called when there are bugs in our code and we have access to an error instance.
  • errorMessage: It's mainly used when the player provides invalid input (e.g., provide invalid faction name when calling ns.singularity.getFactionRep. In this case, we will try to provide a stack trace that points to the player's invalid caller. This is a bit hard because we don't have an error instance with a stack trace. To deal with this problem, we create a new error instance, then remove "unrelated" traces (code in our codebase) and leave only traces of the player's code. This is why errorMessage is so complicated. In parseUnknownError, we don't have this problem (we already have an error instance, we also don't have to manipulate the stack trace), and we use it for a different reason (report bugs in our code, not the player's code).

@catloversg catloversg deleted the pull-request/misc/add-error-cause-to-exceptionAlert-and-Recovery-mode branch November 13, 2024 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants