tinyhumansai/openhuman · error

[transport:local] timed out after ms

Error message

[transport:local] ${method} timed out after ${this.timeoutMs}ms

What it means

LocalTransport arms a per-call AbortController with setTimeout(timeoutMs) (default 30_000ms, constructor third argument) and merges it with the caller's own opts.signal. If fetch rejects and controller.signal.aborted is true, it reports this timeout error. Note the guard checks only controller.signal.aborted, so a caller-initiated abort inside the window is also reported as a timeout.

Solutions

  1. Construct LocalTransport with a larger timeoutMs for known-slow operations (pass 120_000 as the third constructor arg)
  2. Check core liveness first: GET /health on the same rpcUrl origin — if that also hangs, restart the core process rather than raising the timeout
  3. For chat/agent calls, prefer a streaming method so no single call must finish within one window
  4. If you pass opts.signal yourself, make sure you are not aborting it (the message cannot distinguish your abort from the timeout)

Example fix

// before
const t = new LocalTransport(getRpcUrl, getRpcToken);
// after
const t = new LocalTransport(getRpcUrl, getRpcToken, 120_000);
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight liveness so you only pay the long timeout for real work:
async function coreAlive(rpcUrl: string): Promise<boolean> {
  const ctrl = new AbortController();
  const t = setTimeout(() => ctrl.abort(), 2_000);
  try {
    const res = await fetch(rpcUrl, { method: 'GET', signal: ctrl.signal });
    return res.ok || res.status === 404; // listener is up even on unknown GET routes
  } catch { return false; } finally { clearTimeout(t); }
}

Type guard

function isTimeoutError(err: unknown): boolean {
  return err instanceof Error && err.message.includes('timed out after');
}

Try / catch

try {
  return await local.call(method, params);
} catch (err) {
  if (isTimeoutError(err)) {
    await sleep(1_000);
    return await local.call(method, params); // one retry; upgrade timeout if it repeats
  }
  throw err;
}

Prevention

When it happens

Trigger: Any openhuman.* RPC whose server-side work exceeds timeoutMs: long agent turns, memory sync/embedding backfills, flow runs; a hung or paused core process; debugger breakpoints freezing the core; or the caller aborting its signal mid-call (conflated into the same message).

Common situations: The 30s default is too short for LLM-bound methods (chat turns, memory consolidation) on slow local models; core is under CPU load or swapping; core restarted while a request was in flight.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at app/src/services/transport/LocalTransport.ts:68

    }

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);

    // Merge caller signal with timeout signal.
    opts?.signal?.addEventListener('abort', () => controller.abort());

    let response: Response;
    try {
      response = await fetch(rpcUrl, {
        method: 'POST',
        headers,
        body: JSON.stringify(payload),
        signal: controller.signal,
      });
    } catch (err) {
      if (controller.signal.aborted) {
        throw new Error(`[transport:local] ${method} timed out after ${this.timeoutMs}ms`);
      }
      throw err;
    } finally {
      clearTimeout(timeoutId);
    }

    if (!response.ok) {
      const text = await response.text();
      throw new Error(`[transport:local] HTTP ${response.status}: ${text || response.statusText}`);
    }

    const json = (await response.json()) as JsonRpcResponse<T>;

    if (json.error) {
      logErr('[transport:local] ← %s error: %s', method, json.error.message);
      throw new Error(json.error.message ?? 'Core RPC returned an error');
    }
    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {

View on GitHub (pinned to 7491200858)