{"record":{"id":"ba60ed8c343f7ba6","repo":"emilk/egui","slug":"snapshot","errorCode":null,"errorMessage":"{}","messagePattern":"\\{\\}","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/egui_kittest/src/snapshot.rs","lineNumber":967,"sourceCode":"    }\n}\n\nimpl From<SnapshotResults> for Vec<SnapshotError> {\n    fn from(results: SnapshotResults) -> Self {\n        results.into_inner()\n    }\n}\n\nimpl Drop for SnapshotResults {\n    #[track_caller]\n    fn drop(&mut self) {\n        // Don't panic if we are already panicking (the test probably failed for another reason)\n        if std::thread::panicking() {\n            return;\n        }\n        #[expect(clippy::manual_assert)]\n        if self.has_errors() {\n            panic!(\"{}\", self);\n        }\n\n        thread_local! {\n            static UNHANDLED_SNAPSHOT_RESULTS_COUNTER: core::cell::RefCell<usize> = const { core::cell::RefCell::new(0) };\n        }\n\n        if !self.handled {\n            let count = UNHANDLED_SNAPSHOT_RESULTS_COUNTER.with(|counter| {\n                let mut count = counter.borrow_mut();\n                *count += 1;\n                *count\n            });\n\n            #[expect(clippy::manual_assert)]\n            if count >= 2 {\n                panic!(\n                    \"\nMultiple SnapshotResults were dropped without being handled.","sourceCodeStart":949,"sourceCodeEnd":985,"githubUrl":"https://github.com/emilk/egui/blob/441971a776322a482e371775219380eca812cfa9/crates/egui_kittest/src/snapshot.rs#L949-L985","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Handle the Result of try_snapshot/try_image_snapshot calls instead of ignoring them, or use the panicking image_snapshot variant.","Before the harness drops, call Harness::take_snapshot_results and merge into one SnapshotResults via SnapshotResults::extend.","Assert on the collected errors explicitly (e.g. check harness.has_errors() and fail with context) before the drop point.","Ensure early returns/panics in the test still consume or merge the harness's snapshot results."],"exampleFix":"// before: results ignored, panics on drop\nlet mut harness = Harness::new(...);\nharness.try_image_snapshot(\"widget\")?; // error swallowed in some paths\n\n// after: merge results before drop\nlet mut results = harness.take_snapshot_results();\nresults.assert_result(); // or merge into a single SnapshotResults via extend","handlingStrategy":"validation","validationCode":"// before the harness drops\nif harness.has_errors() {\n    let results = harness.take_snapshot_results();\n    results.assert_result(); // or fail with your own message\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always consume snapshot results (assert_result / take_snapshot_results) before the harness goes out of scope.","Do not ignore Result values from try_snapshot/try_image_snapshot APIs.","Use the panicking snapshot variants when you want automatic failure reporting.","In tests with early returns, add an explicit result-handling step on every exit path (or use a guard/defer pattern)."],"tags":["snapshot-testing","panic","rust","testing"],"backgroundTag":"invalid-state-transition","analyzedSha":"441971a776322a482e371775219380eca812cfa9","analyzedAt":"2026-09-12T04:29:21.500Z","contentChangedAt":"2026-09-12T04:29:21.500Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}