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.
  • Source badge and filter — lines VoiceThere writes itself (language checks, language switches, voice settings changes) carry a VoiceThere badge; your own lines carry Agent. Filter by source and by system event group. These lines do not count toward your agent-log overage. See System log events.
  • 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 effective 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.

Paid plans can enable agent log overage billing on the project billing settings panel so storage can grow past the included plan cap (overage credits apply). When overage is off, logs roll off at your plan cap or an elevated rollover ceiling if you had overage on, grew past the plan limit, then turned overage off — your current row count is frozen as the new max until you delete data or re-enable overage. Limits also 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

Toggle agent log overage billing on the project billing settings panel. See Billing & usage credits for wallet packs, metered cash, and how credits appear on your usage statement.

Overage billing & usage credits

On paid plans, when agent log overage billingis enabled, log lines past your plan's monthly included entry cap settle to usage credits instead of rolling off immediately. The included cap uses the same perProjectMax numbers as the plan comparison table (for example Advanced includes 150,000 stored entries per project per UTC calendar month). VoiceThere counts rows by created_at in the current UTC month — not your rolling storage cap alone.

Overflow entries debit the project wallet at 1 usage credit per 1,000 log entries (metered on raw entry count). Free projects never settle agent-log overage credits. When overage is off, storage stays on soft rollover and FIFO at your plan cap (or elevated rollover ceiling) with no usage-credit debits for extra lines.

Turn the toggle on the project Billing settings panel. Metered cash invoices and printable usage statements are described in Billing & usage credits.

Find things faster

The box above the filters on the Agent logs page takes a short query. Press Enter to apply it; the level, source, event, field and message controls below update to match, and changing any of them rewrites the box.

  • level:error: one of debug, info, warn, error.
  • source:voicethere: all, agent or voicethere.
  • event:language_switch: a system event group, language_id, language_switch or voice.
  • peerId=client-1: one JSON field filter, with dots for nested keys such as call.peer.id=client-1.
  • Anything else is message text. Wrap it in double quotes to keep the spaces, as in "peer joined". A word with an unknown prefix, such as room:lobby, is searched as plain text.

A value the box does not accept, such as level:loud, is listed under the box and ignored; the rest of the query still applies.

Filters in the address

The Agent logs page reads its filters from the address, so a filtered view can be bookmarked or shared with a teammate in the same organization. The page asks the server for the matching lines, so older lines in the range show up even when they are not among the most recent ones.

  • level: debug, info, warn or error.
  • q: text the message must contain, ignoring case.
  • from and to: ISO 8601 timestamps. Lines created at or after from and before to are listed. The range cannot be longer than 90 days, and to cannot be in the future.

Example: /projects/<project-id>/logs?level=error&q=TypeError&from=2026-10-08T00:00:00Z&to=2026-10-09T00:00:00Z. The metrics Agent tab links here from each top error. Active filters show as chips above the list. Remove one, or choose Clear filters, to widen the view. If a value in the address is not valid, the page shows every log and says so.

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
voicethere projects logs list --project <project-id> --level error --from 2026-10-07T12:00:00Z --to 2026-10-08T12:00:00Z

--severity is an alias for --level. --from and --to take ISO 8601 timestamps and keep only logs created inside that window, which is how you open the lines behind a row in the Agent metrics tab. 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, from and to (ISO 8601; an invalid timestamp, a to in the future, to not after from, or a range over 90 days returns HTTP 400).

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 Settings → 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