kitao/pyxel · critical

Pyxel not initialized

Error message

Pyxel not initialized

What it means

This panic comes from the `pyxel()` accessor in pyxel-core, which unwraps the thread-local `Option<Pyxel>` singleton. It fires whenever any Pyxel API is used before the singleton has been installed by `init`. The library guards all state access through this accessor, so an uninitialized access cannot be recovered from — it panics instead of returning a Result.

Source

Thrown at crates/pyxel-core/src/pyxel.rs:48

    pub(crate) system: System,
    pub(crate) resource: Resource,
    pub(crate) input: Input,
    pub(crate) graphics: Option<Graphics>,
}

static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);

// Singleton
thread_local! {
    static PYXEL: &'static RefCell<Option<Pyxel>> =
        Box::leak(Box::new(RefCell::new(None)));
}

pub fn pyxel() -> RefMut<'static, Pyxel> {
    PYXEL.with(|instance| {
        let instance: &'static RefCell<Option<Pyxel>> = instance;
        RefMut::map(instance.borrow_mut(), |instance| {
            instance.as_mut().expect("Pyxel not initialized")
        })
    })
}

fn set_pyxel(instance: Pyxel) {
    // The leaked RefCell keeps the owner address stable through Python module
    // cleanup; replace its value only when the next initialization is ready.
    PYXEL.with(|current| *current.borrow_mut() = Some(instance));
}

// Lifecycle callbacks

type ResetCallback = Option<Box<dyn FnMut(Option<String>) + Send>>;

thread_local! {
    static RESET_CALLBACK: &'static RefCell<ResetCallback> =
        Box::leak(Box::new(RefCell::new(None)));
}

View on GitHub (pinned to 50f9bd7778)

Solutions

  1. Call `pyxel::init(width, height, ...)` before any other Pyxel API call.
  2. Ensure all Pyxel calls run on the same thread that called init (the singleton is thread-local).
  3. If tearing down and re-initializing, re-run init before further API use.
  4. Gate API usage behind an `is_initialized` check / IS_INITIALIZED flag in wrapper code.

Example fix

// before
let img = pyxel_core::graphics::image(0); // panics: Pyxel not initialized
// after
pyxel::init(160, 120, None, None, None, None);
let img = pyxel_core::graphics::image(0);
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: guard calls behind init state
fn ensure_pyxel_ready() -> Result<(), String> {
    if !IS_INITIALIZED.load(std::sync::atomic::Ordering::Acquire) {
        return Err("call pyxel::init() before using the API".into());
    }
    Ok(())
}

Try / catch

// Rust panics cannot be caught by Result; use catch_unwind at the boundary
let result = std::panic::catch_unwind(|| {
    pyxel_core::graphics::image(0)
});
match result {
    Ok(img) => use_image(img),
    Err(_) => eprintln!("Pyxel API used before init()"),
}

Prevention

When it happens

Trigger: Calling any pyxel-core/pyxel API (graphics, audio, input, tilemap, etc.) that internally calls `pyx()`/`pyxel()` before `pyxel::init(...)` has completed, or after init/quit teardown has cleared the instance. Also calling from a different thread than the one where init ran, since the singleton is thread-local.

Common situations: Calling a Pyxel function at module top-level or in a static initializer before init; calling Pyxel APIs from a worker thread; calling APIs after the app has quit and cleanup ran; forgetting init in a test harness that exercises drawing/audio helpers directly.

Related errors


AI-assisted analysis of kitao/pyxel@50f9bd7778 (2026-09-03). Data as JSON: /api/errors/8d1c26d5be7de838. Report an issue: GitHub.