tinyhumansai/openhuman · error

build custom tokio runtime for tauri async surface

Error message

build custom tokio runtime for tauri async surface

What it means

Panic payload on Runtime::new() in the desktop Tauri host: the shell builds a custom multi-thread tokio runtime (sized with AGENT_WORKER_STACK_BYTES, 16 MiB worker stacks) because sub-agent delegation overflows the default 2 MiB stack. This expect fires when the runtime itself cannot be constructed — almost always a resource-limit failure (rlimit on threads/resident memory) rather than a logic error.

Source

Thrown at app/src-tauri/src/lib.rs:2234

    // enough for that single tower, but sub-agent delegation (issue #3159
    // / PR #3155) re-tipped the scale: the standalone `openhuman-core`
    // CLI server still aborted with `Abort trap: 6 / fatal runtime error:
    // stack overflow` once an orchestrator delegated. PR #3155 raised the
    // standalone server to 16 MiB; the desktop Tauri host is the *same*
    // tower running on a *different* runtime and needs the same headroom.
    // Share the constant with the rest of `src/core/*` via
    // [`openhuman_core::core::runtime::AGENT_WORKER_STACK_BYTES`] so all
    // multi-thread runtimes that may host an agent turn stay in sync.
    //
    // Must happen before any `tauri::async_runtime::*` call, otherwise
    // `set(...)` panics with "runtime already initialized".
    {
        let custom_runtime = tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .thread_stack_size(openhuman_core::core::runtime::AGENT_WORKER_STACK_BYTES)
            .max_blocking_threads(openhuman_core::core::runtime::MAX_BLOCKING_THREADS)
            .build()
            .expect("build custom tokio runtime for tauri async surface");
        let handle = custom_runtime.handle().clone();
        // Tauri docs: "you cannot drop the underlying TokioRuntime."
        // Leak it so its lifetime matches the process.
        std::mem::forget(custom_runtime);
        tauri::async_runtime::set(handle);
    }

    // Initialize Sentry for the Tauri shell (desktop host) process before any
    // other startup work. Reads `OPENHUMAN_TAURI_SENTRY_DSN` at runtime first,
    // then falls back to the value baked in at compile time via the release
    // workflow. Missing/empty DSN ⇒ `sentry::init` returns a no-op guard.
    //
    // The guard is held for the entire lifetime of `run()` so events queued
    // during shutdown still flush. Only invoked here (and not in `main.rs`)
    // so renderer/GPU CEF helper subprocesses (re-exec'd via
    // `tauri::cef_entry_point`) and the `OpenHuman core …` in-process core
    // path do NOT spin up a second client — those have their own reporting
    // surfaces.

View on GitHub (pinned to 7491200858)

Solutions

  1. Raise OS thread/memory limits (ulimit -u, launchd plist) so tokio can spawn its worker pool
  2. Check for another runtime already running in the same process (nested Runtime::new can fail)
  3. Report the full panic backtrace alongside the core log if construction still fails
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at app/src-tauri/src/lib.rs:2234 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/623474f9022d329d. Report an issue: GitHub.