diff --git a/v2/internal/app/app_dev.go b/v2/internal/app/app_dev.go
index 4e668bc9a..018cb226c 100644
--- a/v2/internal/app/app_dev.go
+++ b/v2/internal/app/app_dev.go
@@ -221,7 +221,7 @@ func CreateApp(appoptions *options.App) (*App, error) {
eventHandler := runtime.NewEvents(myLogger)
ctx = context.WithValue(ctx, "events", eventHandler)
- messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler, appoptions.ErrorFormatter)
+ messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler, appoptions.ErrorFormatter, appoptions.DisablePanicRecovery)
// Create the frontends and register to event handler
desktopFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher)
diff --git a/v2/internal/app/app_production.go b/v2/internal/app/app_production.go
index 4c217b17c..9eb0e5a66 100644
--- a/v2/internal/app/app_production.go
+++ b/v2/internal/app/app_production.go
@@ -82,7 +82,7 @@ func CreateApp(appoptions *options.App) (*App, error) {
ctx = context.WithValue(ctx, "buildtype", "production")
}
- messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler, appoptions.ErrorFormatter)
+ messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler, appoptions.ErrorFormatter, appoptions.DisablePanicRecovery)
appFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher)
eventHandler.AddFrontend(appFrontend)
diff --git a/v2/internal/frontend/dispatcher/dispatcher.go b/v2/internal/frontend/dispatcher/dispatcher.go
index 60a99f467..24a43cfef 100644
--- a/v2/internal/frontend/dispatcher/dispatcher.go
+++ b/v2/internal/frontend/dispatcher/dispatcher.go
@@ -11,38 +11,42 @@ import (
)
type Dispatcher struct {
- log *logger.Logger
- bindings *binding.Bindings
- events frontend.Events
- bindingsDB *binding.DB
- ctx context.Context
- errfmt options.ErrorFormatter
+ log *logger.Logger
+ bindings *binding.Bindings
+ events frontend.Events
+ bindingsDB *binding.DB
+ ctx context.Context
+ errfmt options.ErrorFormatter
+ disablePanicRecovery bool
}
-func NewDispatcher(ctx context.Context, log *logger.Logger, bindings *binding.Bindings, events frontend.Events, errfmt options.ErrorFormatter) *Dispatcher {
+func NewDispatcher(ctx context.Context, log *logger.Logger, bindings *binding.Bindings, events frontend.Events, errfmt options.ErrorFormatter, disablePanicRecovery bool) *Dispatcher {
return &Dispatcher{
- log: log,
- bindings: bindings,
- events: events,
- bindingsDB: bindings.DB(),
- ctx: ctx,
- errfmt: errfmt,
+ log: log,
+ bindings: bindings,
+ events: events,
+ bindingsDB: bindings.DB(),
+ ctx: ctx,
+ errfmt: errfmt,
+ disablePanicRecovery: disablePanicRecovery,
}
}
func (d *Dispatcher) ProcessMessage(message string, sender frontend.Frontend) (_ string, err error) {
- defer func() {
- if e := recover(); e != nil {
- if errPanic, ok := e.(error); ok {
- err = errPanic
- } else {
- err = fmt.Errorf("%v", e)
+ if !d.disablePanicRecovery {
+ defer func() {
+ if e := recover(); e != nil {
+ if errPanic, ok := e.(error); ok {
+ err = errPanic
+ } else {
+ err = fmt.Errorf("%v", e)
+ }
}
- }
- if err != nil {
- d.log.Error("process message error: %s -> %s", message, err)
- }
- }()
+ if err != nil {
+ d.log.Error("process message error: %s -> %s", message, err)
+ }
+ }()
+ }
if message == "" {
return "", errors.New("No message to process")
diff --git a/v2/pkg/options/options.go b/v2/pkg/options/options.go
index 282a25691..082ac48cd 100644
--- a/v2/pkg/options/options.go
+++ b/v2/pkg/options/options.go
@@ -98,6 +98,9 @@ type App struct {
// DragAndDrop options for drag and drop behavior
DragAndDrop *DragAndDrop
+
+ // DisablePanicRecovery disables the panic recovery system in messages processing
+ DisablePanicRecovery bool
}
type ErrorFormatter func(error) any
diff --git a/website/docs/reference/options.mdx b/website/docs/reference/options.mdx
index efcc67961..9d999f421 100644
--- a/website/docs/reference/options.mdx
+++ b/website/docs/reference/options.mdx
@@ -487,6 +487,13 @@ services of Apple and Microsoft.
Name: EnableFraudulentWebsiteDetection
Type: `bool`
+### DisablePanicRecovery
+
+DisablePanicRecovery disables the automatic recovery from panics in message processing. By default, Wails will recover from panics in message processing and log the error. If you want to handle panics yourself, set this to `true`.
+
+Name: DisablePanicRecovery
+Type: `bool`
+
### Bind
A slice of struct instances defining methods that need to be bound to the frontend.
diff --git a/website/src/pages/changelog.mdx b/website/src/pages/changelog.mdx
index b7486186d..6a40bdde2 100644
--- a/website/src/pages/changelog.mdx
+++ b/website/src/pages/changelog.mdx
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added "Branding" section to `wails doctor` to correctly identify Windows 11 [#3891](https://github.com/wailsapp/wails/pull/3891) by [@ronen25](https://github.com/ronen25)
- Added `-skipembedcreate` flag to build and dev command to improve compile and recompile speed [#4143](https://github.com/wailsapp/wails/pull/4143) by @josStorer
+- Added `DisablePanicRecovery` option to allow handle panics manually [#4136](https://github.com/wailsapp/wails/pull/4136) by [@APshenkin](https://github.com/APshenkin)
### Fixed
- Fixed typescript generation of maps with key of array of structs by @joshuapare in [#4209](https://github.com/wailsapp/wails/pull/4209)