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 levelerrorto 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
fieldsJSON. Session error rows includefields.kind = session_error,fields.code,fields.projectId,fields.sessionId(orchestrator session id), and optionalfields.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,agentorvoicethere.event:language_switch: a system event group,language_id,language_switchorvoice.peerId=client-1: one JSON field filter, with dots for nested keys such ascall.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 asroom: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,warnorerror.q: text the message must contain, ignoring case.fromandto: ISO 8601 timestamps. Lines created at or afterfromand beforetoare listed. The range cannot be longer than 90 days, andtocannot 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/logsGET /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)
| Code | When |
|---|---|
| AGENT_HANDLER_FAILED | Agent handler threw; errorHook ran; runner ending session |
| AGENT_CHILD_CRASHED | Child process exit or unhandled bundle load failure |
| AGENT_CHILD_CRASHED_RESTARTED | Child crashed under restart_child — see agent crash policy |
| RUNNER_INTERNAL | Runner-side failure (e.g. crash TTS could not play) |
| SESSION_END_FAILED | Session marked failed on teardown |
| IDLE_TIMEOUT_CALLBACK_FAILED | Agent onIdleTimeout hook threw |
| IDLE_TIMEOUT_CALLBACK_TIMED_OUT | onIdleTimeout exceeded 30s grace |
| SESSION_IDLE_TIMEOUT | Informational — 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.
| Code | When |
|---|---|
| PROVISIONING_FAILED | Session start job failed or HTTP error |
| PROVISIONING_TIMEOUT | Async provisioning poll exceeded timeout |
| WEBRTC_CONNECTION_FAILED | Peer connection state became failed |
| WEBRTC_CONNECTION_CLOSED | Unexpected close before graceful disconnect |
| WEBRTC_CONNECT_TIMEOUT | waitForConnected 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.