Pumpkin-MC/Pumpkin · error · SpawnError

{message}

Error message

{message}

What it means

`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.

Solutions

  1. Check whether the plugin/runtime is shutting down before spawning; abort pending work gracefully.
  2. Keep a valid, live runtime handle (clone it where needed) instead of spawning on a dropped executor.
  3. Log the `SpawnError`'s message to identify the underlying cause reported by the host.
  4. Retry only if the failure is transient (e.g. temporary overload); otherwise surface the error to the plugin caller.

Example fix

// before
runtime.spawn(work); // panics or loses error on shutdown
// after
if let Err(e) = runtime.spawn(work) {
    log::error!("task not spawned: {e}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check runtime liveness before spawning:
if shutting_down.load(Ordering::Acquire) { return; }

Type guard

fn can_spawn(rt: &Option<RuntimeHandle>) -> bool { rt.is_some() }

Try / catch

match runtime.spawn(work) {
    Ok(fut) => { /* attach */ },
    Err(e) => log::error!("spawn failed: {e}"),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09). Data as JSON: /api/errors/e4ce9404cdb2cd36. Report an issue: GitHub.

Appendix: source

Thrown at crates/pumpkin-plugin-runtime/src/spawn.rs:8

use std::{future::Future, pin::Pin};

use thiserror::Error;

pub type SpawnFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;

#[derive(Clone, Debug, Error)]
#[error("{message}")]
pub struct SpawnError {
    message: String,
}

impl SpawnError {
    #[must_use]
    pub fn new(message: impl Into<String>) -> Self {
        Self {
            message: message.into(),
        }
    }
}

/// Spawns runtime work without selecting or constructing an async runtime.
pub trait RuntimeSpawner: Send + Sync + 'static {
    /// Transfers ownership of a future that must eventually be polled or
    /// dropped when spawning succeeds.
    fn spawn(&self, task: SpawnFuture) -> Result<(), SpawnError>;

View on GitHub (pinned to 8d4639e25a)