You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 05389dd
Browse filesBrowse the repository at this point in the historyBrowse files
Replace the never-released crashOnUncaughtJsExceptions flag with the
cross-runtime uncaughtErrorPolicy contract:
{ "uncaughtErrorPolicy": "report" } // default: report, keep running
{ "uncaughtErrorPolicy": "throw" } // rethrow unprevented errors natively
"throw" keeps the same mechanics (deferred NativeScriptFatalJSException
from a clean scope-free frame, JS stack in reason/userInfo) under an
honest name: it is a throw, not a crash guarantee - the app terminates
only if no native handler catches it. Unknown values warn once and fall
back to "report".
discardUncaughtJsExceptions is deprecated but still honored in full for
now (routes to __onDiscardedError, skips the fatal log, suppresses the
throw policy); it logs a one-time deprecation warning pointing at
preventDefault() and uncaughtErrorPolicy.
Copy file name to clipboardExpand all lines: docs/error-handling.md
+19-13Lines changed: 19 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Error handling
2
2
3
-
The runtime implements the WHATWG error model at the global level: uncaught JavaScript exceptions and unhandled promise rejections are dispatched as cancelable events on `globalThis`, native `NSException`s round-trip into JavaScript with the original object attached, and `interop.escapeException` forwards a JavaScript throw to a native caller as a real `@throw`. By default nothing crashes the app — reporting is opt-out per error (`preventDefault()`), and crashing is opt-in (`crashOnUncaughtJsExceptions`).
3
+
The runtime implements the WHATWG error model at the global level: uncaught JavaScript exceptions and unhandled promise rejections are dispatched as cancelable events on `globalThis`, native `NSException`s round-trip into JavaScript with the original object attached, and `interop.escapeException` forwards a JavaScript throw to a native caller as a real `@throw`. By default nothing crashes the app — reporting is opt-out per error (`preventDefault()`), and rethrowing unprevented errors natively is opt-in (`uncaughtErrorPolicy: "throw"`).
-`error` and `unhandledrejection` are `cancelable`; `preventDefault()` suppresses every downstream consequence (legacy hooks, fatal log, error modal, `crashOnUncaughtJsExceptions`).
43
+
-`error` and `unhandledrejection` are `cancelable`; `preventDefault()` suppresses every downstream consequence (legacy hooks, fatal log, error modal, the `uncaughtErrorPolicy: "throw"` rethrow).
44
44
- Events fire even if app code overwrites `globalThis.dispatchEvent` — native dispatch goes through closures captured at startup.
45
45
- A listener that throws does not stop the remaining listeners; the thrown value is routed to the fatal reporting tail directly (never recursively dispatched as another `error` event).
46
46
- The events also fire on worker globals. A worker's unhandled rejection dispatches `unhandledrejection` on the worker's own global first; only when unprevented does it continue to the worker-global `onerror` and then to the main isolate's `worker.onerror`, mirroring uncaught worker errors.
@@ -149,27 +149,33 @@ The accessor is uniform across all cases; underneath:
149
149
|---|---|
150
150
| Synthesized escape |`userInfo[TNSJavaScriptStackTraceKey]` (`@"JavaScriptStack"`), plus `userInfo[TNSJavaScriptEscapeStackTraceKey]` (`@"JavaScriptEscapeStack"`) when the `escapeException` call site differs from the error's origin; also appended to `reason`|
151
151
| Rethrown original `NSException`| attached as an associated object (identity and `userInfo` are untouched); the string combines the origin stack and the escape site |
152
-
|`crashOnUncaughtJsExceptions` fatal (`NativeScriptFatalJSException`) |`userInfo[TNSJavaScriptStackTraceKey]`, also in `reason`|
152
+
|`uncaughtErrorPolicy: "throw"` fatal (`NativeScriptFatalJSException`) |`userInfo[TNSJavaScriptStackTraceKey]`, also in `reason`|
153
153
154
154
`tns_javascriptStackTrace` and the two `userInfo` keys are the stable contract for crash-SDK integrations.
155
155
156
156
## Configuration
157
157
158
-
Both flags live in the app's `package.json`, both default to off:
158
+
`uncaughtErrorPolicy`in the app's `package.json` is the uncaught-error contract, unified across NativeScript runtimes (9.1+):
159
159
160
-
| Flag | Effect |
161
-
|---|---|
162
-
|`discardUncaughtJsExceptions`| Unprevented errors call `__onDiscardedError` instead of `__onUncaughtError` and skip the fatal log. Also disables `crashOnUncaughtJsExceptions`. |
163
-
|`crashOnUncaughtJsExceptions`| After an unprevented error is reported, the app crashes with a real `NSException` (JS stack in `reason` and `userInfo`), thrown from a clean frame on the runtime loop so crash reporters capture it properly. |
160
+
```jsonc
161
+
{ "uncaughtErrorPolicy":"report" } // default: report and keep running
162
+
{ "uncaughtErrorPolicy":"throw" } // unprevented errors are rethrown natively
163
+
```
164
+
165
+
-`"report"` — after the event dispatch and legacy hooks, log the fatal message and keep the app alive.
166
+
-`"throw"` — additionally rethrow the error as a real `NSException` (`NativeScriptFatalJSException`, JS stack in `reason` and `userInfo`), from a clean frame on the runtime loop. This is a **throw, not a crash guarantee**: the app terminates only if no native handler catches it — which also means crash reporters capture it properly when it does.
167
+
- Unknown values log a warning once and fall back to `"report"`.
168
+
169
+
Deprecated: `discardUncaughtJsExceptions` is still honored in full for now — unprevented errors route to `__onDiscardedError` instead of `__onUncaughtError`, the fatal log is skipped, and any `"throw"` policy is suppressed — but it logs a deprecation warning. Migrate to an `error`/`unhandledrejection` listener calling `preventDefault()` (per-error, more precise) and `uncaughtErrorPolicy`.
164
170
165
171
Terminal-path decision table for an uncaught error / unhandled rejection:
Native side — for the `NSUncaughtExceptionHandler`/signal layer, read `exception.tns_javascriptStackTrace` (or the `userInfo` keys) to attach the JS stack to crashes that never pass through the JS event layer (escaped exceptions, `crashOnUncaughtJsExceptions`).
202
+
Native side — for the `NSUncaughtExceptionHandler`/signal layer, read `exception.tns_javascriptStackTrace` (or the `userInfo` keys) to attach the JS stack to crashes that never pass through the JS event layer (escaped exceptions, `uncaughtErrorPolicy:"throw"`).
0 commit comments