cool-lizard-26153
12/19/2025, 1:56 PMunhandled exception while running the job task
Traceback (most recent call last):
File \"/usr/local/lib/python3.10/site-packages/opentelemetry/util/_decorator.py\", line 71, in async_wrapper
return await func(*args, **kwargs) # type: ignore
File \"/usr/local/lib/python3.10/site-packages/livekit/agents/ipc/job_proc_lazy_main.py\", line 286, in _traceable_entrypoint
await self._job_entrypoint_fnc(job_ctx)
File \"/opt/deployment/voice-agents-backend/main.py\", line 355, in entrypointx
await agentToRun.entrypoint(ctx)
File \"/opt/deployment/voice-agents-backend/screening_assistant.py\", line 2205, in entrypoint
await session.start(
File \"/usr/local/lib/python3.10/site-packages/livekit/agents/voice/agent_session.py\", line 595, in start
raise RuntimeError(
RuntimeError: Only one `AgentSession` can be the primary at a time. If you want to ignore primary designation, use session.start(record=False).", "exc_info": "RuntimeError: Only one `AgentSession` can be the primary at a time. If you want to ignore primary designation, use session.start(record=False).
this is happening after upgrading livekit sdk from v1.0.12 to v1.0.20tall-airline-16756
12/19/2025, 1:56 PMtall-airline-16756
12/19/2025, 1:56 PMAgentSession can be the primary at a time." I'll help you resolve it.
Short answer
• Start the new session with recording disabled: use await session.start(..., record=False). That prevents the session from becoming the primary recorder and avoids the conflict during handoffs.
Why this works
• The newer SDK enforces a single primary AgentSession when recording/observability is enabled. Disabling recording for the handoff session prevents duplicate primary designation.
Next steps I recommend
1. Update the handoff code where you call session.start(...) to pass record=False. Example:
await session.start(agent=your_agent, room=ctx.room, record=False)
1. If you require recording/observability for these sessions, consider:
◦ Only allowing one session to start with record=True (the intended primary), or
◦ Disable project/agent-level Agent Observability in the LiveKit dashboard for flows where multiple agents may be active.
Quick question to help further
• Do you need recording for these handoff sessions, or is it acceptable to disable recording during handoffs? If you need recording, tell me how you expect primary ownership to be handled so I can suggest specific patterns.
If you want, paste the session.start call you currently use and I’ll show the exact change.
Sources: Streamline Troubleshooting with Agent Observabilitycool-lizard-26153
12/19/2025, 1:58 PMtall-airline-16756
12/19/2025, 1:58 PMrecord=True.
Short answer
• Yes. Recording is session-scoped, not agent-scoped. If you start the AgentSession with record=True, recording continues across the handoff and both agents will be recorded.
Important details
• Handoffs switch the active agent within the same `AgentSession`; they do not start a new session.
• You cannot stop recording for the second agent by passing record=False during the handoff — that parameter applies when the session is started and persists for the session lifetime.
• There’s no supported way to dynamically disable recording mid-session; recording stops only when the session ends.
If you need per-agent separate recordings, tell me whether you can:
• end the first session and start a new session for the second agent (so each session can have its own record setting), or
• keep a continuous session and accept a single combined recording.
Tell me which option you prefer and I’ll suggest the exact code changes.
Sources: https://blog.livekit.io/streamline-troubleshooting-with-agent-observability/#/portal/signup| | https://blog.livekit.io/streamline-troubleshooting-with-agent-observability/#/portal|cool-lizard-26153
12/19/2025, 2:02 PMrecord setting),tall-airline-16756
12/19/2025, 2:03 PMrecord setting.
1) Gracefully end the first session
• Call await session.shutdown(drain=True) to let pending speech finish, then close any room connections if needed (e.g., await session.disconnect() or your cleanup flow).
2) Create a new AgentSession for the second agent
• Initialize a fresh AgentSession with the same audio/LLM/TTS config but the record value you want for the second agent.
3) Start the new session in the same room
• Start the new session pointing at the same room reference so call continuity is preserved.
Minimal Python example (adapt to your code structure):
# end first session
await first_session.shutdown(drain=True)
# optional: await first_session.disconnect()
# create new session (record=True for second agent)
second_session = AgentSession(
stt=..., llm=..., tts=..., vad=...,
record=True
)
# start second session in same room
await second_session.start(agent=second_agent, room=ctx.room)
Key notes
• Recording is session-scoped. Ending the first session and starting a new one gives each session its own record behavior.
• Use shutdown(drain=True) to avoid cutting off speech.
• Ensure you reuse the same room object/reference so the caller stays in the same room/connection.
If you want, paste your current session.start / shutdown code and I’ll show the exact edits.
Sources: Agents (Node.js) | livekit/livekit_composite | DeepWiki | Job lifecycle | LiveKit docscool-lizard-26153
12/19/2025, 2:13 PMtall-airline-16756
12/19/2025, 2:14 PMconst info = await egressClient.startRoomCompositeEgress('room-name', {
file: new EncodedFileOutput({ filepath: 'recordings/session-123.mp4', output: { case: 's3', value: new S3Upload({ /* ... */ }) } })
}, { layout: 'speaker' });
• Stop egress:
await egressClient.stopEgress(info.egressId);
Notes and best practices
• Recording is room-scoped: as long as the egress runs, all agent handoffs are recorded in one continuous file.
• Do not stop/restart egress during handoffs (that creates separate recordings and gaps).
• Use AutoEgress for fully automated start-on-call if you’re using SIP dispatch rules.
• If you need per-agent metadata inside the single recording, emit markers/events to your logging system or include timestamped metadata; the recording itself is a continuous stream.
If you want, tell me:
• Which SDK/language you use for egress (Node/TS, Python, or REST) and whether you use SIP dispatch rules; I’ll give exact code/config snippets for your setup. Sources: RoomComposite Egress | LiveKit Docs | Agents and handoffs | LiveKit docs | Egress API | LiveKit docs | sip | livekit/livekit_composite | DeepWiki | Auto egress | LiveKit docs