tinyhumansai/openhuman · error
Core RPC token unavailable in Tauri; local RPC auth cannot b
Error message
Core RPC token unavailable in Tauri; local RPC auth cannot be satisfied
What it means
Thrown by callCoreRpc when running inside Tauri and the bearer token could not be obtained: the shell mints a per-launch hex token for the embedded core (handed over via run_server_embedded_with_ready), and every local RPC must present it. When both the cloud-stored token and the Tauri core_rpc_token command yield nothing, the request cannot be authenticated and is refused before hitting the wire.
Source
Thrown at app/src/services/coreRpcClient.ts:679
const effectiveTimeoutMs = resolvePerCallTimeoutMs(timeoutMs);
const payload: JsonRpcRequestBody = {
jsonrpc: '2.0',
id: nextJsonRpcId++,
method: normalizedMethod,
params: params ?? {},
};
try {
const [rpcUrl, token] = await Promise.all([getCoreRpcUrl(), getCoreRpcToken()]);
coreRpcLog('HTTP request', { id: payload.id, method: payload.method });
if (normalizedMethod === 'openhuman.auth_store_session') {
coreRpcLog('[rpc] auth_store_session routing', {
rpcUrl,
tokenSource: getStoredCoreToken() ? 'cloud-stored' : 'local-resolved',
});
}
if (isTauri() && !token) {
throw new Error('Core RPC token unavailable in Tauri; local RPC auth cannot be satisfied');
}
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// Bound the fetch. Without this a hung core sidecar would block every
// caller (and the UI) forever. We use a manual AbortController +
// setTimeout rather than AbortSignal.timeout() so test fake timers can
// drive the abort deterministically. Per-call `timeoutMs` (clamped) lets
// legitimately-slow RPCs such as first-launch `app_state_snapshot`
// (#2156) opt into a longer-but-still-bounded budget.
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), effectiveTimeoutMs);
let response: Response;
try {
if (isTauri() && rpcUrlNeedsShellRelay(rpcUrl)) {
// Self-hosted runtime on a LAN IP — the secure `tauri://localhost`View on GitHub (pinned to a221052e0d)
Solutions
- Await the app's boot gates (CoreStateProvider / BootCheckGate) before issuing RPCs from new code — they exist precisely to sequence this
- Restart the app; a fresh launch re-mints the token via start_core_process
- Check the core actually booted: core logs / the health endpoint on the core port
- Retry the call after a short delay — token availability is transient during boot
- If developing with an external core, set OPENHUMAN_CORE_TOKEN or use the documented reuse env var
Example fix
// before
const snap = await callCoreRpc({ method: 'openhuman.app_state_snapshot' });
// after
await coreReady; // gate from CoreStateProvider / boot promise
const snap = await callCoreRpc({ method: 'openhuman.app_state_snapshot' }); Defensive patterns
Strategy: retry
Validate before calling
// Wait for boot before the first RPC instead of racing the token
await coreStateReady; // exposed by CoreStateProvider / BootCheckGate
await callCoreRpc({ method: 'openhuman.app_state_snapshot' }); Try / catch
for (let attempt = 0; attempt < 5; attempt++) {
try {
return await callCoreRpc(payload);
} catch (e) {
if (e instanceof Error && e.message.includes('token unavailable')) {
await delay(500 * 2 ** attempt); // core still booting — token arrives shortly
continue;
}
throw e;
}
} Prevention
- Sequence new RPCs behind the app's boot gates rather than firing on mount
- After a core restart, clear the cached token before the next call (the restart path already does)
- If the token never appears, check that the core process actually started (health endpoint) — retrying a dead core is pointless
When it happens
Trigger: An RPC fires before the core process is ready (the shell has not yet minted/exposed the token — e.g. a service or effect racing app boot), the core crashed at startup so the token command fails/returns nothing, or the Tauri IPC layer (CEF window.ipc.postMessage path) fails synchronously.
Common situations: First-launch races (early fetches like app_state_snapshot firing before BootCheckGate/CoreStateProvider complete); core crash-loop on boot (bad config, corrupted workspace); running the UI against a core that exited; CEF IPC quirks referenced by the Sentry TAURI-REACT issues in the source comment.
Related errors
- Invalid ${paramName}: '${value}'. Must be a valid integer ID
- Core RPC HTTP ${response.status}: ${text || response.statusT
- Not running in Tauri
- Not running in Tauri
- RPC token not provided and ${tokenPath} could not be read. P
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/4ba7b20a622d8963.
Report an issue: GitHub.