emilk/egui · error

{}

Error message

{}

What it means

This panic fires when a Harness is dropped while it still holds unhandled errors (has_errors() returns true), i.e. snapshot or harness errors accumulated during the test were never surfaced. It intentionally skips panicking if the thread is already panicking so the original test failure is not masked. The panic displays the whole Harness via Display, which summarizes the collected errors.

Source

Thrown at crates/egui_kittest/src/snapshot.rs:967

    }
}

impl From<SnapshotResults> for Vec<SnapshotError> {
    fn from(results: SnapshotResults) -> Self {
        results.into_inner()
    }
}

impl Drop for SnapshotResults {
    #[track_caller]
    fn drop(&mut self) {
        // Don't panic if we are already panicking (the test probably failed for another reason)
        if std::thread::panicking() {
            return;
        }
        #[expect(clippy::manual_assert)]
        if self.has_errors() {
            panic!("{}", self);
        }

        thread_local! {
            static UNHANDLED_SNAPSHOT_RESULTS_COUNTER: core::cell::RefCell<usize> = const { core::cell::RefCell::new(0) };
        }

        if !self.handled {
            let count = UNHANDLED_SNAPSHOT_RESULTS_COUNTER.with(|counter| {
                let mut count = counter.borrow_mut();
                *count += 1;
                *count
            });

            #[expect(clippy::manual_assert)]
            if count >= 2 {
                panic!(
                    "
Multiple SnapshotResults were dropped without being handled.

View on GitHub (pinned to 441971a776)

Solutions

  1. Handle the Result of try_snapshot/try_image_snapshot calls instead of ignoring them, or use the panicking image_snapshot variant.
  2. Before the harness drops, call Harness::take_snapshot_results and merge into one SnapshotResults via SnapshotResults::extend.
  3. Assert on the collected errors explicitly (e.g. check harness.has_errors() and fail with context) before the drop point.
  4. Ensure early returns/panics in the test still consume or merge the harness's snapshot results.

Example fix

// before: results ignored, panics on drop
let mut harness = Harness::new(...);
harness.try_image_snapshot("widget")?; // error swallowed in some paths

// after: merge results before drop
let mut results = harness.take_snapshot_results();
results.assert_result(); // or merge into a single SnapshotResults via extend
Defensive patterns

Strategy: validation

Validate before calling

// before the harness drops
if harness.has_errors() {
    let results = harness.take_snapshot_results();
    results.assert_result(); // or fail with your own message
}

Prevention

When it happens

Trigger: A Harness that recorded errors (failed image_snapshot calls or snapshot comparison results) is dropped at end of scope without all snapshot results having been taken/merged, and no earlier panic is in flight.

Common situations: Calling fallible snapshot APIs (try_image_snapshot) and ignoring the Result, then letting the harness go out of scope; early-returning from a test after a failed assertion while the harness still holds pending snapshot results; creating a second harness in the same test whose results are never merged.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of emilk/egui@441971a776 (2026-09-12). Data as JSON: /api/errors/ba60ed8c343f7ba6. Report an issue: GitHub.