{"record":{"id":"5c2bbd0ac4c343f3","repo":"bevyengine/bevy","slug":"attempted-to-access-or-drop-non-send-data-from","errorCode":null,"errorMessage":"Attempted to access or drop non-send data {} from thread {:?} on a thread {:?}. This is not allowed. Aborting.","messagePattern":"Attempted to access or drop non-send data (.+?) from thread (.+?) on a thread (.+?)\\. This is not allowed\\. Aborting\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/bevy_ecs/src/storage/non_send.rs","lineNumber":78,"sourceCode":"            self.data.drop(1, self.is_present().into());\n        }\n    }\n}\n\nimpl NonSendData {\n    /// The only row in the underlying `BlobArray`.\n    const ROW: usize = 0;\n\n    /// Validates that the access to `NonSendData` is only done on the thread they were created from.\n    ///\n    /// # Panics\n    /// This will panic if called from a different thread than the one it was inserted from.\n    #[inline]\n    fn validate_access(&self) {\n        #[cfg(feature = \"std\")]\n        if self.origin_thread_id != Some(std::thread::current().id()) {\n            // Panic in tests, as testing for aborting is nearly impossible\n            panic!(\n                \"Attempted to access or drop non-send data {} from thread {:?} on a thread {:?}. This is not allowed. Aborting.\",\n                self.type_name,\n                self.origin_thread_id,\n                std::thread::current().id()\n            );\n        }\n\n        // TODO: Handle no_std non-send.\n        // Currently, no_std is single-threaded only, so this is safe to ignore.\n        // To support no_std multithreading, an alternative will be required.\n        // Remove the #[expect] attribute above when this is addressed.\n    }\n\n    /// Returns true if the data is populated.\n    #[inline]\n    pub fn is_present(&self) -> bool {\n        self.is_present\n    }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_ecs/src/storage/non_send.rs#L60-L96","documentation":"NonSend<T> resources are not Send: bevy only permits them to be accessed - and dropped - on the exact thread they were created on. This panic fires from NonSend's validate_access when the recorded origin thread id does not match std::thread::current().id(), meaning non-send data crossed threads through a path that promised it would not. In no_std (single-threaded) builds the check is skipped.","triggerScenarios":"Dropping the World (or removing the NonSend resource) on a different thread than where it was inserted; accessing NonSend data from a schedule running on worker threads; constructing an App in one thread and dropping it in another (tests, FFI hosts, embedded runtimes).","commonSituations":"Test harnesses that build an App inside thread::spawn and then drop it on main; engines/runtimes that relocate work between threads; window/GPU handles stored as NonSend touched after the main thread changed.","solutions":["Create, access, and drop the World/NonSend resource on the same thread - typically main.","If the data must be touched elsewhere, send ownership to the origin thread via a channel, or restructure it into Send data (raw handle plus thread-local context).","In tests, construct and tear down the App inside the same test body instead of moving it between threads."],"exampleFix":"// before\nlet app = thread::spawn(|| { let mut a = App::new(); a.insert_non_send_resource(Handle::new()); a }).join().unwrap();\ndrop(app); // NonSend dropped on the wrong thread -> panic\n\n// after\nlet mut app = App::new();\napp.insert_non_send_resource(Handle::new());\n// insert, access and drop all happen on this same thread","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the World/App lifecycle on one thread; send data between threads, never the World.","Use NonSend<T> params only in schedules that run on the creating (main) thread; use plain resources for Send data.","In multithreaded test harnesses, construct and drop the App inside the same test body."],"tags":["bevy","ecs","non-send","thread-safety","panic","thread-affinity"],"backgroundTag":"thread-affinity-violation","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}