diff --git a/v2/internal/app/app_dev.go b/v2/internal/app/app_dev.go
index 4e668bc9a57..018cb226c19 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 4c217b17c4a..9eb0e5a666c 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 60a99f46796..24a43cfef53 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 282a25691ac..082ac48cdd8 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 efcc67961fb..9d999f42195 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 e34a51eff68..bfac5d8d79c 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 -m build flag for dev command not working when recompiling in [#4141](https://github.com/wailsapp/wails/pull/4141) by @josStorer