Skip to content

Pass panics to the fallback error handler#24240

Merged
alice-i-cecile merged 26 commits into
bevyengine:mainfrom
SpecificProtagonist:panic-to-error
Jun 1, 2026
Merged

Pass panics to the fallback error handler#24240
alice-i-cecile merged 26 commits into
bevyengine:mainfrom
SpecificProtagonist:panic-to-error

Conversation

@SpecificProtagonist

@SpecificProtagonist SpecificProtagonist commented May 11, 2026

Copy link
Copy Markdown
Contributor

Objective

Currently, a panic (whether from engine or user code, as there is little distinction) takes down the entire app with it. Instead the user should be able to decide how the error is handled. This is currently not possible except by writing your own executor and setting it for all relevant schedules.

See for comparison Godot's policy on exceptions:

Why does Godot not use exceptions?

We believe games should not crash, no matter what. If an unexpected situation happens, Godot > will print an error (which can be traced even to script), but then it will try to recover as > gracefully as possible and keep going.

Unity will also log an error and then continue if user code throws an exception. I believe Unreal does too for exceptions coming from Blueprints. Similarly, many web servers will respond with an error to a request that threw an exception, but will not crash the server itself.

This PR does not enable this behavior by default, but makes it user-configurable.

Also fixes #19109
Also (I think) fixes #7434

Solution

Instead of rethrowing panics, hand them to the FallbackErrorHandler.

If the panic was thrown by an error handler in the first place, we don't need to pass it back to a handler again. I've added a way for the error handler to signal that it's the source of the panic.

The constructed error is created without a backtrace, as the default panic handler already prints it when instructed to via RUST_LIB_BACKTRACE/RUST_BACKTRACE.

Panics will not be turned into errors on no_std projects.

Potential work for a future PR:

  • if a error handler has been specified with e.g. queue_handled, use this error handler instead of the fallback error handler
  • if a command panics, still apply the remaining commands in the buffer?

Testing

See added panic_to_error test

@SpecificProtagonist SpecificProtagonist added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 11, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in ECS May 11, 2026
Err(payload) if PANIC_ORIGINATES_FROM_ERROR_HANDLER.replace(false) => {
(None, Err(payload))
}
// We can ignore the panic payload here, as it will have already been printed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

By default, the panic handler will have already printed the panic payload, but we could add it to the error message given to the error handler too.

Err(_) => {
let err = BevyError::new_with_backtrace(
Severity::Panic,
"System panicked",

@SpecificProtagonist SpecificProtagonist May 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm using only an error message here, but if desired I could create a structured error that can be BevyError::downcast_refed.

Edit: The panic payload isn't Sync, so it can't be included in the error type, so this wouldn't be particularly useful

Comment thread crates/bevy_ecs/src/error/handler.rs

@chescock chescock left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, being able to recover from panics seems like a really important part of making Bevy robust!

Comment thread crates/bevy_ecs/src/schedule/executor/multi_threaded.rs Outdated
Comment thread crates/bevy_ecs/src/schedule/executor/multi_threaded.rs Outdated
Comment thread crates/bevy_ecs/src/schedule/executor/multi_threaded.rs Outdated
@alice-i-cecile alice-i-cecile requested a review from NthTensor May 13, 2026 15:16
@alice-i-cecile alice-i-cecile added the M-Release-Note Work that should be called out in the blog due to impact label May 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note.

Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes.

@chescock chescock left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, this version was much easier for me to follow!

Comment thread crates/bevy_ecs/src/schedule/executor/multi_threaded.rs Outdated
@chescock

Copy link
Copy Markdown
Contributor

Oh, I just remembered run conditions! Do we need to do something similar for them? I don't think we even catch_unwind them, so I have no idea what happens if they panic.

@SpecificProtagonist

Copy link
Copy Markdown
Contributor Author

Good catch. I think that's because before #11906 they were evaluated in the executor task. I'm not sure whether the original reason for the catch_unwinds (#7448) still holds after that PR anyways.

Comment thread _release-content/release-notes/panics-to-errors.md Outdated
Comment thread _release-content/release-notes/panics-to-errors.md Outdated
SpecificProtagonist and others added 2 commits May 22, 2026 12:11
Co-authored-by: Gonçalo Rica Pais da Silva <bluefinger@gmail.com>
Co-authored-by: Gonçalo Rica Pais da Silva <bluefinger@gmail.com>
@SpecificProtagonist SpecificProtagonist added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 22, 2026
Comment thread _release-content/release-notes/panics-to-errors.md Outdated
@alice-i-cecile alice-i-cecile enabled auto-merge May 24, 2026 08:55
@mockersf mockersf dismissed their stale review June 1, 2026 19:35

resolved

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 1, 2026
Merged via the queue into bevyengine:main with commit 18d106d Jun 1, 2026
38 checks passed
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in ECS Jun 1, 2026
chescock added a commit to chescock/bevy that referenced this pull request Jul 14, 2026
# Objective

Improve the handling of commands that panic.  

Currently, if a command panics, any unapplied commands are left in the
command queue. This means they will get run, but at an unpredictable
time in the future.

And when running in `no_std`, cleanup is not run at all and the commands
simply leak.

## Solution

Catch panics from commands and pass them to the fallback error handler,
just as we now do for systems from bevyengine#24240. This means if the error
handler is set to something non-panicking like `warn`, then
`flush_commands()` will never panic and all commands in the queue will
be applied.

Introduce a RAII guard during command application that will drop any
commands still in the queue and perform cleanup during unwinding, even
on `no_std`.

To make the command's type name available in the error handler, add a
field to the RAII guard that gets written by
`consume_command_and_get_size` before applying the command.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible M-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Panics cannot be caught on iOS Add panicking system test to bevy_ecs

5 participants