tinyhumansai/openhuman · error

[skill-latency] tool chain on thread ${event.thread_id} took

Error message

[skill-latency] tool chain on thread ${event.thread_id} took ${latency.elapsedMs}ms across ${latency.toolCount} tool(s) — exceeds the ${SKILL_TOOL_CHAIN_TARGET_MS}ms target

What it means

Observability-only log from ChatRuntimeProvider (#4273 AC3): finishChain closed the per-turn tool-chain latency window and the elapsed time from first tool to last tool across toolCount calls exceeded SKILL_TOOL_CHAIN_TARGET_MS (60s). Nothing fails or blocks — the turn completes; the log exists to track skill/tool-chain latency regressions against the target.

Source

Thrown at app/src/providers/ChatRuntimeProvider.tsx:1106

          output_tokens: event.total_output_tokens,
        });

        // Close the tool-chain latency window and surface overruns of the 60s
        // target (#4273, AC3). Observability only — never blocks the turn.
        const latency = skillLatencyRef.current.finishChain(
          segmentDeliveryKey(event.thread_id, event.request_id),
          { ok: true }
        );
        if (latency) {
          rtLog('skill_tool_chain_latency', {
            thread: event.thread_id,
            request: event.request_id,
            elapsed_ms: latency.elapsedMs,
            tools: latency.toolCount,
            within_target: latency.withinTarget ? 'true' : 'false',
          });
          if (!latency.withinTarget) {
            console.warn(
              `[skill-latency] tool chain on thread ${event.thread_id} took ${latency.elapsedMs}ms ` +
                `across ${latency.toolCount} tool(s) — exceeds the ${SKILL_TOOL_CHAIN_TARGET_MS}ms target`
            );
          }
        }

        // Parallel (forked) turn: resolve only its own lane. The primary turn's
        // stream / status / lifecycle / active marker may still be running, so
        // we must NOT clear them here. Segmented parallel turns already
        // persisted via `onSegment` (keyed by thread+request); a single-bubble
        // parallel turn persists its full response now.
        if (
          event.request_id !== undefined &&
          store.getState().chatRuntime.parallelRequestThreads[event.request_id] !== undefined
        ) {
          const parallelRequestId = event.request_id;
          dispatch(recordChatTurnUsage(chatTurnUsagePayload(event)));
          if (!event.segment_total && event.full_response.length > 0) {

View on GitHub (pinned to 7491200858)

Solutions

  1. Inspect which tools dominated the chain (pair with per-tool timing events on the same thread/request)
  2. Treat as a performance signal: long-running tools (shell, generation) or retry loops are usual culprits
  3. File/tune the specific slow tool rather than acting on the aggregate alone
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at app/src/providers/ChatRuntimeProvider.tsx:1106 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/5fba99241a5f589a. Report an issue: GitHub.