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
- Raise OS thread/memory limits (ulimit -u, launchd plist) so tokio can spawn its worker pool
- Check for another runtime already running in the same process (nested Runtime::new can fail)
- 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.