Skip to content

Add context messages to BevyError#24528

Merged
alice-i-cecile merged 16 commits into
bevyengine:mainfrom
cookie1170:bevy-error-ergonomics
Jun 17, 2026
Merged

Add context messages to BevyError#24528
alice-i-cecile merged 16 commits into
bevyengine:mainfrom
cookie1170:bevy-error-ergonomics

Conversation

@cookie1170

@cookie1170 cookie1170 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Objective

Add a context() extension method to Result<T> and Option<T> like anyhow

Solution

Add a Vec<String> field to InnerBevyError to store context messages added via context()

Fixes #19714.

Testing

Added the context unit test to test messages produced by context() and a context_downcasting unit test to test that downcasting still works when using .context

Add a `context` method to `Result` and `Option` and some extra utilities to `ResultSeverityExt`
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events M-Release-Note Work that should be called out in the blog due to impact D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Jun 4, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in ECS Jun 4, 2026
@alice-i-cecile alice-i-cecile added this to the 0.20 milestone Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

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.

@alice-i-cecile alice-i-cecile self-requested a review June 4, 2026 05:11
@Shatur

Shatur commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Thank you for working on this! This should close #19714.

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

@SpecificProtagonist SpecificProtagonist 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.

Generally in favor of both the severity shorthands and the error context, though they could be done in separate PRs because they're independent. The fix to backtrace filtering also shouldn't be part of this PR.

}
}

impl<T> ContextExt<T> for Option<T> {

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.

This seems odd to me and might be a bit confusing to use. Attaching a context to an option turns the context into an error? And options work with .with_context but not with .with_severity (as map_severity can't work with options)?

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.

having an Option that's None usually means something failed, i.e. getting an element from an array, so you can attach a context message to it to turn it into an error that can be displayed. anyhow does the same thing so i just copied it from there really :p
having with_severity on an Option means that it'll need to turn into an error with some message, but if you then use context on it now you have 2 messages (i.e. some context message: option is none), which is different from if you first used context and then with_severity (you'll just get some context message)

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.

This is odd to me too.

What you describe can be done with Option::ok_or and Option::ok_or_else:

let value = option.ok_or_else(|| format!("thing"))?;

And the with_context documentation suggests you are adding context to an existing result. That is not what is being done here.

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.

yeah fair, i just added it to Option because anyhow has it for Option as well, so i imagine people might expect it to be there for BevyError too

Comment thread crates/bevy_ecs/src/error/bevy_error.rs Outdated
Comment thread crates/bevy_ecs/src/error/bevy_error.rs Outdated
@alice-i-cecile

Copy link
Copy Markdown
Member

Generally in favor of both the severity shorthands and the error context, though they could be done in separate PRs because they're independent. The fix to backtrace filtering also shouldn't be part of this PR.

Agreed, I would prefer this split into three :)

@cookie1170 cookie1170 changed the title Improve BevyError ergonomics Add context messages to BevyError Jun 8, 2026
@cookie1170

cookie1170 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

fair! i've split the shorthands into #24555 and got rid of the backtrace changes for now

@kfc35 kfc35 added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Jun 9, 2026

@kfc35 kfc35 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.

This looks good to me. The release note is easy to understand as well.

@alice-i-cecile alice-i-cecile requested a review from NthTensor June 9, 2026 18:27

@NthTensor NthTensor 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.

Looks good. I am, separately, interested in the idea of attaching "hints" or "help messages" to errors.

@kfc35 kfc35 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 Jun 9, 2026
@alice-i-cecile alice-i-cecile enabled auto-merge June 9, 2026 20:12

@MarcGuiselin MarcGuiselin 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.

Looks good overall, but I want to challenge the design here which assumes several things:

  • There will only ever be one error
  • That error will have a sequence of causes, or context
  • Context is always a string

anyhow makes no such assumptions. It implements context internally via a ContextError:

pub(crate) struct ContextError<C, E> {
    pub context: C,
    pub error: E,
}

A context in anyhow can be understood as a branching tree of errors + context starting at the latest context.

Given this builder: Err(A4).context("B3").with_context(|| Err(C2).context("D1").unwrap_err())

You get an error that looks something like this:

ContextError {
   context: ContextError {
      context: "D1",
      error: C2,
   },
   error: ContextError {
      context: "B3",
      error: A4,
   }
}

Anyhow can correctly implement Display and Debug on its Error type and all children recursively:

We can also introspect the error/context and check whether it is the exact one we expect. This is very useful for tests or for recovering from errors.

Comment thread crates/bevy_ecs/src/error/bevy_error.rs Outdated
}
}

impl<T> ContextExt<T> for Option<T> {

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.

This is odd to me too.

What you describe can be done with Option::ok_or and Option::ok_or_else:

let value = option.ok_or_else(|| format!("thing"))?;

And the with_context documentation suggests you are adding context to an existing result. That is not what is being done here.

Comment thread crates/bevy_ecs/src/error/bevy_error.rs
Comment thread crates/bevy_ecs/src/error/bevy_error.rs Outdated
auto-merge was automatically disabled June 13, 2026 02:02

Head branch was pushed to by a user without write access

@cookie1170

Copy link
Copy Markdown
Contributor Author

Looks good overall, but I want to challenge the design here which assumes several things:

* There will only ever be one error

* That error will have a sequence of causes, or context

* Context is always a string

anyhow makes no such assumptions. It implements context internally via a ContextError:

pub(crate) struct ContextError<C, E> {
    pub context: C,
    pub error: E,
}

A context in anyhow can be understood as a branching tree of errors + context starting at the latest context.

Given this builder: Err(A4).context("B3").with_context(|| Err(C2).context("D1").unwrap_err())

You get an error that looks something like this:

ContextError {
   context: ContextError {
      context: "D1",
      error: C2,
   },
   error: ContextError {
      context: "B3",
      error: A4,
   }
}

i'm not sure that's a very common usecase, i certainly haven't seen a context be another error, especially not one with a context (which would be formatted a bit oddly i'm pretty sure)
in my mind, a context is like a human-readable message (or multiple) attached to the error to indicate where it happened, so imo it makes sense for it to be a string

@MarcGuiselin

Copy link
Copy Markdown
Contributor

i'm not sure that's a very common usecase, i certainly haven't seen a context be another error, especially not one with a context (which would be formatted a bit oddly i'm pretty sure)

I agree, I'm using an extreme use-case to illustrate how anyhow maintains the shape of the errors and the context.

If bevy errors are going to contain similar functionality, we must acknowledge how our model compares to anyhow and what we loose in the process, such as the original shape of the accumulated errors and context. Maybe that's fine, especially for a first version :)

in my mind, a context is like a human-readable message (or multiple) attached to the error to indicate where it happened, so imo it makes sense for it to be a string

In anyhow, a context is essentially a dyn Display. So it can be an error, a string or any other source of information that indicates why and where something failed.

Another benefit of this is that you are only lazily evaluating the context when it needs to be displayed instead of always formatting and producing a string when there is an error, since sometimes the whole context might not be needed.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 17, 2026
Merged via the queue into bevyengine:main with commit 8bf04c6 Jun 17, 2026
38 checks passed
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in ECS Jun 17, 2026
@cookie1170 cookie1170 deleted the bevy-error-ergonomics branch June 17, 2026 05:08
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 D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes 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.

Add the ability to attach context to BevyError

8 participants