slint-ui/slint · error

platform already initialized

Error message

platform already initialized

What it means

`init_no_event_loop` in the testing backend installs the testing platform via `set_platform`, which can only succeed once per process. If a platform is already installed (a previous test init, or any code that triggered backend initialization), the call returns an error and the `.expect("platform already initialized")` panics. Slint allows exactly one platform initialization per process lifetime.

Solutions

  1. Restructure tests so the whole binary has one init: put multiple scenarios inside a single #[test] function, as the function's docs recommend.
  2. Use a shared `std::sync::Once` guard around the init call so it executes exactly once per process.
  3. Split tests into separate binaries (one #[test] per integration test file) so each process initializes the platform once.
  4. Alternatively call `init_integration_test_with_mock_time()`/`_with_system_time()`, which are designed for the same one-time role — but still only once.

Example fix

// before
#[test] fn a() { slint_testing::init_no_event_loop(); /* ok */ }
#[test] fn b() { slint_testing::init_no_event_loop(); /* panics */ }

// after: one init per process
static INIT: std::sync::Once = std::sync::Once::new();
fn ensure_init() {
    INIT.call_once(|| slint_testing::init_no_event_loop());
}
#[test] fn a() { ensure_init(); /* ... */ }
#[test] fn b() { ensure_init(); /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

use std::sync::Once;
static TEST_INIT: Once = Once::new();
pub fn ensure_testing_init() {
    TEST_INIT.call_once(|| slint_testing::init_no_event_loop());
}

Try / catch

// tolerate repeated init at call site
if TEST_INIT.is_completed() { return; }
slint_testing::init_no_event_loop();

Prevention

When it happens

Trigger: Calling `slint_testing::init_no_event_loop()` (or the related init_integration_test_* functions) more than once in the same process, e.g. multiple #[test] functions in one test binary, or after something else already created a window/backend.

Common situations: Integration test crates with several #[test] fns (each test binary runs them in one process); combining testing-backend init with a doc test; an earlier test created a Slint component before the init call, auto-initializing the platform.

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 slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/d7c109bb9f8bf2cc. Report an issue: GitHub.

Appendix: source

Thrown at internal/backends/testing/lib.rs:45

pub mod systest;

/// Initialize the testing backend without support for event loop.
/// This means that each test thread can use its own backend, but global functions that needs
/// an event loop such as `slint::invoke_from_event_loop` or `Timer`s won't work.
/// Must be called before any call that would otherwise initialize the rendering backend.
/// Calling it when the rendering backend is already initialized will panic.
///
/// Note that for animations and timers, the changes in the system time will be disregarded.
/// Instead, use [`mock_elapsed_time()`] to advance the simulate (mock) time Slint uses.
pub fn init_no_event_loop() {
    i_slint_core::platform::set_platform(Box::new(testing_backend::TestingBackend::new(
        testing_backend::TestingBackendOptions {
            mock_time: true,
            threading: false,
            ..Default::default()
        },
    )))
    .expect("platform already initialized");
}

/// Initialize the testing backend with support for simple event loop.
/// This function can only be called once per process, so make sure to use integration
/// tests with only one `#[test]` function. (Or in a doc test)
/// Must be called before any call that would otherwise initialize the rendering backend.
/// Calling it when the rendering backend is already initialized will panic.
///
/// Note that for animations and timers, the changes in the system time will be disregarded.
/// Instead, use [`mock_elapsed_time()`] to advance the simulate (mock) time Slint uses.
pub fn init_integration_test_with_mock_time() {
    i_slint_core::platform::set_platform(Box::new(testing_backend::TestingBackend::new(
        testing_backend::TestingBackendOptions {
            mock_time: true,
            threading: true,
            ..Default::default()
        },
    )))

View on GitHub (pinned to bb937076de)