{"record":{"id":"e4ce9404cdb2cd36","repo":"Pumpkin-MC/Pumpkin","slug":"message","errorCode":null,"errorMessage":"{message}","messagePattern":"\\{message\\}","errorType":"exception","errorClass":"SpawnError","httpStatus":null,"severity":"error","filePath":"crates/pumpkin-plugin-runtime/src/spawn.rs","lineNumber":8,"sourceCode":"use std::{future::Future, pin::Pin};\n\nuse thiserror::Error;\n\npub type SpawnFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;\n\n#[derive(Clone, Debug, Error)]\n#[error(\"{message}\")]\npub struct SpawnError {\n    message: String,\n}\n\nimpl SpawnError {\n    #[must_use]\n    pub fn new(message: impl Into<String>) -> Self {\n        Self {\n            message: message.into(),\n        }\n    }\n}\n\n/// Spawns runtime work without selecting or constructing an async runtime.\npub trait RuntimeSpawner: Send + Sync + 'static {\n    /// Transfers ownership of a future that must eventually be polled or\n    /// dropped when spawning succeeds.\n    fn spawn(&self, task: SpawnFuture) -> Result<(), SpawnError>;","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-plugin-runtime/src/spawn.rs#L1-L26","documentation":"`SpawnError` is the thiserror-based error type for task spawning in pumpkin-plugin-runtime; its `Display` simply renders the caller-supplied `message` string. Producers wrap whatever the underlying spawn failure was (runtime shut down, executor rejected the task, capacity limits) into this struct with a human-readable description.","triggerScenarios":"Any API in `pumpkin-plugin-runtime` that spawns a `SpawnFuture` fails — e.g. spawning on a runtime that has already been shut down, or a plugin host rejecting a spawn for policy/capacity reasons — and constructs `SpawnError { message }` with the detail.","commonSituations":"Plugins spawning background tasks during shutdown or world unload; spawning after the server runtime handle was dropped; host environments restricting async task creation for untrusted plugins.","solutions":["Check whether the plugin/runtime is shutting down before spawning; abort pending work gracefully.","Keep a valid, live runtime handle (clone it where needed) instead of spawning on a dropped executor.","Log the `SpawnError`'s message to identify the underlying cause reported by the host.","Retry only if the failure is transient (e.g. temporary overload); otherwise surface the error to the plugin caller."],"exampleFix":"// before\nruntime.spawn(work); // panics or loses error on shutdown\n// after\nif let Err(e) = runtime.spawn(work) {\n    log::error!(\"task not spawned: {e}\");\n}","handlingStrategy":"try-catch","validationCode":"// Check runtime liveness before spawning:\nif shutting_down.load(Ordering::Acquire) { return; }","typeGuard":"fn can_spawn(rt: &Option<RuntimeHandle>) -> bool { rt.is_some() }","tryCatchPattern":"match runtime.spawn(work) {\n    Ok(fut) => { /* attach */ },\n    Err(e) => log::error!(\"spawn failed: {e}\"),\n}","preventionTips":["Track shutdown state and skip spawns during unload.","Keep cloned runtime handles alive as long as the plugin may spawn.","Log SpawnError messages to surface the host's underlying cause."],"tags":["async","task-spawn","runtime","plugin-runtime"],"backgroundTag":"network-request-failed","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}