linebender/druid · error

Application is already running

Error message

Application is already running

What it means

`Application::run` panics if called on an `Application` instance that has already been run. The application tracks a `running` flag in a `RefCell`; calling `run` twice on the same instance would start a second platform event loop, which is invalid.

Solutions

  1. Create a fresh `Application` for each run instead of reusing the previous instance
  2. Restructure the code so `run` is called exactly once, from one code path
  3. If a restart is needed, spawn a new process rather than re-running the same `Application`

Example fix

// before
let app = Application::new().unwrap();
app.run(None);
app.run(None); // panics

// after
let app = Application::new().unwrap();
app.run(None); // once; make a new Application to run again
Defensive patterns

Strategy: type-guard

Validate before calling

// Track run state in the caller:
let mut has_run = false;
if !has_run { app.run(None); has_run = true; }

Type guard

fn can_run(running: bool) -> bool { !running }

Try / catch

// Rust panics are not catchable here by design; guard the call site:
if !app_has_run() { app.run(handler); }

Prevention

When it happens

Trigger: Calling `app.run(handler)` a second time on the same `Application` value (or a clone/reborrow of it) after the first `run` set `state.running = true`.

Common situations: Restarting the app from a menu/callback by calling `run` again instead of creating a new `Application`; calling run in both a setup path and a main path.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10). Data as JSON: /api/errors/8f28d766fae576b4. Report an issue: GitHub.

Appendix: source

Thrown at druid-shell/src/application.rs:131

        util::assert_main_thread_or_main_unclaimed();
        GLOBAL_APP.with(|global_app| global_app.borrow().clone())
    }

    /// Start the `Application` runloop.
    ///
    /// The provided `handler` will be used to inform of events.
    ///
    /// This will consume the `Application` and block the current thread
    /// until the `Application` has finished executing.
    ///
    /// # Panics
    ///
    /// Panics if the `Application` is already running.
    pub fn run(self, handler: Option<Box<dyn AppHandler>>) {
        // Make sure this application hasn't run() yet.
        if let Ok(mut state) = self.state.try_borrow_mut() {
            if state.running {
                panic!("Application is already running");
            }
            state.running = true;
        } else {
            panic!("Application state already borrowed");
        }

        // Run the platform application
        self.backend_app.run(handler);

        // This application is no longer active, so clear the global reference
        GLOBAL_APP.with(|global_app| {
            *global_app.borrow_mut() = None;
        });
        // .. and release the main thread
        util::release_main_thread();
        // .. and mark as done so a new sequence can start
        APPLICATION_CREATED
            .compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)

View on GitHub (pinned to 0f8b1195e4)