VoiceThere

Agent logs & session errors

VoiceThere stores structured log lines from your agent bundle — emitted via agentLog or overridden console.debug|log|info|warn|error in @voicethere/agent. Lines appear in the project dashboard (Project → Agent logs), on each session detail page, and via the CLI voicethere projects logs list.

The former dashboard Errors tab is retired. Structured session failures (crashes, handler throws, provisioning issues) are stored as error-level agent log rows with stable codes in the message and JSON fields — filter with level error in the dashboard or CLI.

Emitting logs from your agent

Prefer agentLog for structured fields you want to search later. Plain console calls are captured with a default message and optional structured payload when you pass objects.

import { agentLog } from "@voicethere/agent";

agentLog("peer joined", {
  level: "info",
  fields: { peerId: "client-1", room: "lobby" },
});

// console.* is also captured (level maps 1:1)
console.warn("inventory low", { sku: "potion", count: 2 });

Log levels

Supported levels (same in agent protocol and dashboard filters):

debug, info, warn, error

Dashboard

  • Project → Agent logs — newest project-wide lines with search, level filter, and optional JSON field filters (dot paths such as peerId). Use level error to see session failures.
  • Session detail → Logs — same controls scoped to one session; open a session from the logs table or the sessions list.
  • Each row shows timestamp, level, message, and expandable fields JSON. Session error rows include fields.kind = session_error, fields.code, fields.projectId, fields.sessionId (orchestrator session id), and optional fields.stack_trace.

Plan limits & soft rollover

Log storage is rolling — when you exceed your plan cap, the oldest lines are removed and the newest are kept. On cap pressure, VoiceThere uses soft rollover: non-error rows are deleted before error-level rows so session failures stay visible longer. The same ordering applies per project and per session. Limits depend on your project subscription (see the cap hint on the dashboard and the plans comparison table):

  • Maximum stored lines per project
  • Maximum stored lines per session
  • Lines per second (excess lines are dropped)
  • Retention in days

CLI

List logs for a project or filter to one session:

voicethere projects logs list --project <project-id>
voicethere projects logs list --project <project-id> --session <orchestrator-session-id>
voicethere projects logs list --project <project-id> --q "peer joined" --level info
voicethere projects logs list --session <orchestrator-session-id> --severity error

--severity is an alias for --level. Session failures appear as error rows with messages like [AGENT_HANDLER_FAILED] ….

API

Same filters as the dashboard — see Control plane API:

  • GET /api/v1/projects/:projectId/logs
  • GET /api/v1/projects/:projectId/sessions/:sessionId/logs

Query parameters: q, level, limit, fieldPath, fieldValue.

Session error data channel (runtime)

In addition to persisted logs, runners emit matching session_error events on the voice-control data channel so clients can react immediately. Legacy agent_error JSON is still accepted and mapped to AGENT_CHILD_CRASHED.

{
  "type": "session_error",
  "code": "AGENT_HANDLER_FAILED",
  "message": "Sorry, something went wrong.",
  "session_id": "<orchestrator-session-id>",
  "project_id": "<uuid>",
  "build_id": "<uuid>",
  "stack": "Error: …\n  at …",
  "recoverable": false,
  "customer_context": { "userId": "u_123" },
  "occurred_at": "2026-06-19T12:00:00.000Z"
}

Error code catalog

Codes are defined in SESSION_ERROR_CODES (platform, runner, client). Persisted error log sources: agent, runner, provisioning.

Runner / agent (remote — on voice-control)

CodeWhen
AGENT_HANDLER_FAILEDAgent handler threw; errorHook ran; runner ending session
AGENT_CHILD_CRASHEDChild process exit or unhandled bundle load failure
AGENT_CHILD_CRASHED_RESTARTEDChild crashed under restart_child — see agent crash policy
RUNNER_INTERNALRunner-side failure (e.g. crash TTS could not play)
SESSION_END_FAILEDSession marked failed on teardown
IDLE_TIMEOUT_CALLBACK_FAILEDAgent onIdleTimeout hook threw
IDLE_TIMEOUT_CALLBACK_TIMED_OUTonIdleTimeout exceeded 30s grace
SESSION_IDLE_TIMEOUTInformational — peer idle limit reached (often paired with session_close)

Client-only (local — never on data channel)

Emitted by @voicethere/client to onSessionError before or without a live WebRTC leg.

CodeWhen
PROVISIONING_FAILEDSession start job failed or HTTP error
PROVISIONING_TIMEOUTAsync provisioning poll exceeded timeout
WEBRTC_CONNECTION_FAILEDPeer connection state became failed
WEBRTC_CONNECTION_CLOSEDUnexpected close before graceful disconnect
WEBRTC_CONNECT_TIMEOUTwaitForConnected timed out

Full enum (12 codes): AGENT_HANDLER_FAILED, AGENT_CHILD_CRASHED, RUNNER_INTERNAL, SESSION_END_FAILED, IDLE_TIMEOUT_CALLBACK_FAILED, IDLE_TIMEOUT_CALLBACK_TIMED_OUT, SESSION_IDLE_TIMEOUT, PROVISIONING_FAILED, PROVISIONING_TIMEOUT, WEBRTC_CONNECTION_FAILED, WEBRTC_CONNECTION_CLOSED, WEBRTC_CONNECT_TIMEOUT.

@voicethere/agent — errorHook

Optional hook in defineAgent runs in the sandboxed child when handler code throws, before the runner plays crash TTS and ends the session. Must not throw.

import { defineAgent, agentLog } from "@voicethere/agent";

defineAgent({
  async errorHook({ sessionId, error, customerContext }) {
    agentLog("error", `session ${sessionId}: ${error.message}`);
  },
  onUserSpeechFinal({ sessionId, text }) {
    if (text.includes("crash")) throw new Error("demo failure");
  },
});

@voicethere/client — onSessionError

import { startSession, connectBrowserSession } from "@voicethere/client/browser";

const provision = await startSession({
  apiBase: sessionServiceBase,
  projectId,
  headers: { Authorization: `Bearer ${apiKey}` },
  onSessionError: (event) => {
    if (event.recoverable) showRetryToast(event.message);
    else showFatalError(event.code, event.message);
  },
});

if (provision.ok) {
  await connectBrowserSession({
    mode: "voice",
    credentials: provision.credentials,
    onSessionError: (event) => analytics.track("session_error", event),
  });
}

Configure crash TTS message

  • Dashboard: project overview → Session settings → Error TTS message.
  • CLI: voicethere projects session-settings set error_message "Sorry, try again."

Crash disconnect vs keep-alive restart: agent_crash_policy — see Agent crash policy.

Legacy URL

/docs/session-errors redirects here with a short note about the retired Errors tab.

← All documentation