incalculable-garage-37123
03/18/2026, 6:45 AM"room_id": "RM_CbYM2j5d97k8"}
12:13:14.628 INFO … session.llm [51dc80f0-f111-4a6f-85f9-f02358fc3fa4]
LLM genearted Response
{"pid": 4082658, "job_id": "AJ_rFaETRqyguby",
"room_id": "RM_CbYM2j5d97k8"}
WARNI… livekit.agents failed to stream event to clients
Traceback (most recent call last):
File
"/home/rashi-aidetic/Documents/Fabrichq/…
line 507, in _send_client_event
event_data = event.model_dump_json()
^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/rashi-aidetic/Documents/Fabrichq/…
line 352, in model_dump_json
return
self.__pydantic_serializer__.to_json(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^…
pydantic_core._pydantic_core.PydanticSer…
Error serializing to JSON:
PydanticSerializationError: Error calling
function `serialize`: AttributeError:
'str' object has no attribute 'audio'
{"pid": 4082658, "job_id": "AJ_rFaETRqyguby",
"room_id": "RM_CbYM2j5d97k8"}
Traceback (most recent call last):
File
"/home/rashi-aidetic/Documents/Fabrichq/automated_call_notifications/venv/lib/python3.
12/site-packages/livekit/agents/voice/client_events.py", line 507, in
_send_client_event
event_data = event.model_dump_json()
^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/rashi-aidetic/Documents/Fabrichq/automated_call_notifications/venv/lib/python3.
12/site-packages/pydantic/main.py", line 352, in model_dump_json
return self.__pydantic_serializer__.to_json(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.PydanticSerializationError: Error serializing to JSON:
PydanticSerializationError: Error calling function `serialize`: AttributeError: 'str'
object has no attribute 'audio'
12:13:14.629 INFO … session.agent [51dc80f0-f111-4a6f-85f9-f02358fc3fa4]
Assistant left the room.
{"pid": 4082658, "job_id": "AJ_rFaETRqyguby",
"room_id": "RM_CbYM2j5d97k8"}
DEBUG… livekit.agents input stream detachedtall-airline-16756
03/18/2026, 6:45 AMtall-airline-16756
03/18/2026, 6:45 AMpip freeze | grep livekit or similar).
• A minimal code snippet showing where you create/send the client event or call session.say() (or any custom event emission) — especially the lines around the error site in your logs.
• Whether you changed any custom event handling, TTS, or overrides to session.say() recently.
• The full stack trace around the call to client_events._send_client_event (you included most — the few surrounding lines where the event is constructed are helpful).
Quick checks and things to try now
1. Inspect event payloads before serialization
• Add a debug log right before the call that sends the event (the code that leads to event.model_dump_json()), and print the event's type and keys/attributes.
• Confirm that the field that should contain audio is not a plain string. The error means the code expected an object with an .audio attribute but got a str.
1. Verify how you call session.say() or emit audio events
• If you call session.say() with just a string (or pass a raw string into a lower-level event), newer package versions may expect a structured audio object instead of a bare string. Ensure you use the API that attaches audio correctly, for example passing text and an audio generator/object as separate parameters rather than putting raw audio data into a string field.
1. Reproduce with the previous working version
• If you still have the older version, test by downgrading to the version that was working to confirm this is a regression:
pip install livekit-agents==previous-version
• If the error disappears after downgrade, that confirms a breaking change in the newer release.
1. Trace pipeline outputs
• If you use pipeline nodes (STT / LLM / TTS), log the output types at each node (stt_node -> llm_node -> tts_node). One node may be returning a raw string where the following step expects a structured audio model.
How I can help next
• Once you paste the version list and the small code snippet around where events are created/sent, I will:
◦ Point out exactly which field is mismatched and show how to construct the correct payload.
◦ Provide a minimal patch/example that converts your current string output into the expected audio object.
◦ Suggest the exact package version to test if you want to confirm a regression.
If you'd like, paste the version output and the small snippet now and I’ll walk through the exact fix step‑by‑step.
Sources: How to detect when an agent has finished speaking | Job lifecycle | LiveKit Documentation | Agent speech and audio | LiveKit Documentation | Pipeline nodes and hooks | LiveKit Documentation | Client SDKs | livekit/livekit_composite | DeepWiki, with interactive elementsincalculable-garage-37123
03/18/2026, 6:50 AMtall-airline-16756
03/18/2026, 6:51 AMawait self.session.say(f"Hello, ...")) and the LiveKit package versions, and that nothing else changed. I’ll focus on the serialization error ("'str' object has no attribute 'audio'") and give concrete troubleshooting steps and a short workaround to get you back to a working state.
What’s happening (brief)
• The code that serializes the client event expects an object with an audio attribute, but it received a plain string. That means session.say(...) (or lower-level event code it calls) is producing/receiving a string where the library now expects a structured audio model/field.
• This appeared right after the package update, so it’s most likely a change in the library’s expected event payload shape (regression or breaking change).
Immediate steps to test and narrow root cause
1. Confirm behavior with a very small change
◦ Replace your call briefly to see if non-audio text-only flow triggers the same failure:
await self.session.say(text="Hello, Am I talking to ...?", allow_interruptions=False)
• If session.say accepts a text= keyword and that avoids the error, it indicates positional string usage is now treated differently by the new version.
1. Log the event payload just before send
◦ Add a debug log right before session.say() or in any wrapper you have, printing the exact argument types:
self._session_logger.log_info(type(greeting), repr(greeting))
• If you can, intercept or patch the library call site (where event.model_dump_json() is called) to print event and event.__dict__ to confirm which attribute is a string.
1. Try a quick downgrade to verify regression
◦ Downgrade livekit-agents to the prior working version (or try a close previous patch) to confirm the update caused the regression:
pip install livekit-agents==1.4.5
• If the error disappears when downgraded, we know the update introduced a breaking change.
Workaround you can try now
• Construct an explicit payload that separates text and audio rather than passing a bare string (if the API supports it). For example:
# pseudo-example — adapt to your API surface
await self.session.say(text=f"Hello, Am I talking to {name}?", audio=None, allow_interruptions=False)
• If the library now expects an audio field (object), explicitly passing audio=None or the proper audio object could avoid the implicit conversion that produced a string in the wrong spot.
What I can do next for you
• If the quick text= test or downgrade confirms the regression, paste the output of the downgrade test (did it fix the issue?) and the debug print of the event payload you see right before serialization.
• With that I’ll:
◦ Show the exact change needed in your code to match the new expected shape (if the API changed).
◦ Create a minimal reproducible snippet you can run locally to confirm the fix.
◦ Suggest the exact package version to pin to if you need a stable rollback.
If you want to continue now, please:
• Try the small text= change and tell me whether the error still appears.
• If possible, add the quick debug print of the greeting variable type/value and paste that output here.
• If you already remember the prior working versions, tell me which livekit-agents version worked for you and I’ll recommend the downgrade command.
I’ll stay with you through the steps — paste the quick test results and I’ll point to the exact fix.
, with interactive elementsincalculable-garage-37123
03/18/2026, 8:30 AM"room_id": "RM_6oqESasCiC4d"}
INFO … session.agent [7a7e14e7-7476-40ac-8499-57f634592c7a]
Assistant entered room, saying greeting.
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
INFO … session.agent [7a7e14e7-7476-40ac-8499-57f634592c7a]
Hello, Am I talking to John Doe?
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:57:57.098 DEBUG… livekit.agents using audio io: `RoomIO` ->
`AgentSession` ->
`TranscriptSynchronizer` -> `RoomIO`
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
DEBUG… livekit.agents using transcript io: `AgentSession` ->
`TranscriptSynchronizer` -> `RoomIO`
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
INFO … session.agent [7a7e14e7-7476-40ac-8499-57f634592c7a]
Agent session started successfully
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:57:57.504 DEBUG… livekit.agents aec warmup active, disabling
interruptions for 3.00s
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:57:57.543 INFO … session.agent [7a7e14e7-7476-40ac-8499-57f634592c7a]
tts_metrics metrics collected
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:57:57.897 DEBUG… livekit.….deepgram Established new Deepgram STT WebSocket
connection:
{"headers": {"dg-project-id":
"c976f576-354b-4460-a92f-db310453ce77", "dg-request-id":
"99cda67d-f0b2-4679-9603-dd314cfad6cb", "Date": "Wed, 18 Mar 2026 08:27:57 GMT"},
"pid": 4113781, "job_id": "AJ_krLD44MaaAN9", "room_id": "RM_6oqESasCiC4d"}
13:57:58.948 INFO … session.llm [7a7e14e7-7476-40ac-8499-57f634592c7a]
LLM genearted Response
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:57:58.950 WARNI… livekit.agents failed to stream event to clients
Traceback (most recent call last):
File
"/home/rashi-aidetic/Documents/Fabrichq/…
line 507, in _send_client_event
event_data = event.model_dump_json()
^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/rashi-aidetic/Documents/Fabrichq/…
line 352, in model_dump_json
return
self.__pydantic_serializer__.to_json(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^…
pydantic_core._pydantic_core.PydanticSer…
Error serializing to JSON:
PydanticSerializationError: Error calling
function `serialize`: AttributeError:
'str' object has no attribute 'audio'
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
Traceback (most recent call last):
File
"/home/rashi-aidetic/Documents/Fabrichq/automated_call_notifications/venv/lib/python3.
12/site-packages/livekit/agents/voice/client_events.py", line 507, in
_send_client_event
event_data = event.model_dump_json()
^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/rashi-aidetic/Documents/Fabrichq/automated_call_notifications/venv/lib/python3.
12/site-packages/pydantic/main.py", line 352, in model_dump_json
return self.__pydantic_serializer__.to_json(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.PydanticSerializationError: Error serializing to JSON:
PydanticSerializationError: Error calling function `serialize`: AttributeError: 'str'
object has no attribute 'audio'
13:57:59.415 INFO … session.egress [7a7e14e7-7476-40ac-8499-57f634592c7a]
Room composite egress EG_WB8dDPhwiphQ
started for
ROOM-candidate-7306600306-20260318135734
(audio)
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:58:00.504 DEBUG… livekit.agents aec warmup expired, re-enabling
interruptions
{"pid": 4113781, "job_id": "AJ_krLD44MaaAN9",
"room_id": "RM_6oqESasCiC4d"}
13:58:04.332 DEBUG… livekit.agents received user transcript
{"user_transcript": "You are talking to John.
So", "language": "en", "transcript_delay": 0.3642466068267822, "pid": 4113781,
"job_id": "AJ_krLD44MaaAN9", "room_id": "RM_6oqESasCiC4d"}
13:58:04.526 DEBUG… livekit.…_detector eou prediction
older version of agent
livekit-agents==1.2.13
current version = 1.4.6tall-airline-16756
03/18/2026, 8:30 AMaudio attribute but is receiving a plain string. Your call await self.session.say(...) is still valid syntactically, but the library’s internals now appear to treat the positional string or certain fields differently and produce an event that fails to serialize.
Concrete next steps you can try now 1) Quick test — explicitly use the text= parameter (you already tried this, which still hit the error). That confirms the issue is deeper in the pipeline (not just positional vs keyword argument).
2) Immediate workaround — force the session to produce a structured reply instead of a raw string. Try calling session.say with a dict-like or object-shaped payload that matches the newer expected event shape. If the public API supports text and audio fields, explicitly pass audio=None to ensure the serializer sees an audio attribute, for example:
# Try explicitly supplying text and an audio field (audio=None) to avoid implicit conversion
await self.session.say(text=f"Hello, Am I talking to {name}?", audio=None, allow_interruptions=False)
If that API signature is not accepted at runtime, another approach is to construct the event yourself using the agent event model (pseudo-code — adapt to your codebase):
from livekit.agents.voice import ClientEvent # adjust import path if different
event = ClientEvent(type="assistant_speech", text=f"Hello, Am I talking to {name}?", audio=None)
await self._send_client_event(event) # call whatever internal send helper your session uses
The goal is to ensure the object given to serialization contains an audio attribute (even if None) rather than being a raw string.
3) Confirm regression via downgrade
• Downgrade to the previously-working version you mentioned:
pip install livekit-agents==1.2.13
• If that removes the error, it confirms a breaking change in 1.4.6 and gives you a working baseline while we identify the exact code change.
4) Add a narrow debug at the serialization point
• If you can, add logging inside the library call site client_events._send_client_event (where event.model_dump_json() is called) to print:
◦ type(event)
◦ event.dict or model_dump()
◦ the specific field(s) that should be audio
This will show which attribute is a plain string and let us craft a precise patch.
How I can help next
• If you want, try the quick workaround (explicit audio=None or constructing a ClientEvent) and tell me whether it prevents the serializer error.
• If the downgrade fixes things, tell me and I’ll:
◦ Recommend pinning to 1.2.13 for now, and
◦ Prepare a minimal reproducible example and suggested patch you can use to open a bug with the maintainers.
• If you can paste the debug output from the serializer (type(event) and event.model_dump() or event.dict), I will point exactly which field to change and provide the exact code snippet to fix it.
If you’d like to proceed, tell me which option you prefer now: try the explicit audio=None call, downgrade to 1.2.13, or add the small debug to capture the event shape — and I’ll guide you step‑by‑step.
, with interactive elementsincalculable-garage-37123
03/18/2026, 11:18 AMtall-airline-16756
03/18/2026, 11:18 AMevent.model_dump_json() in client_events._send_client_event). That serializer expects a structured event object (with an audio attribute) but encountered a plain string somewhere, causing the Pydantic serialization error.
• In short: session.say (or something invoked by it) produced audio for playback, but it also triggers creation/emission of a client event object that failed to serialize. The playback can succeed while the secondary client-event serialization fails.
How to confirm whether session.say (or a downstream step) is the source
1. Add a focused debug right before the library serializes events (or in your own wrapper before calling session.say()), printing the event shape and types:
◦ If you can, patch or temporarily log inside client_events._send_client_event at the line calling `event.model_dump_json()`:
▪︎ Log type(event) and event.model_dump() (or event.__dict__) so you can see which attribute is a string.
◦ If you can't modify the library, add logging right before your session.say(...) call showing the argument types and values:
greeting = f"Hello, Am I talking to {name}?"
self._session_logger.log_info(type(greeting), repr(greeting))
await self.session.say(text=greeting, allow_interruptions=False)
1. Try the explicit audio=None experiment
◦ Call session.say(text=..., audio=None, allow_interruptions=False) to see if supplying an explicit audio attribute avoids creating a malformed event. If this prevents the serializer error, it confirms the serializer expects an audio attribute that is missing or mis-typed.
1. Short alternative test: downgrade to the working version
◦ You noted 1.2.13 worked. Temporarily installing that version (pip install livekit-agents==1.2.13) and verifying the error disappears will confirm the change is due to the library update.
What I can do next
• If you paste the output of one of these:
◦ The event dump from inside _send_client_event (type and model_dump), or
◦ The logs after trying audio=None, or
◦ Whether downgrading to 1.2.13 removes the error—
I will pinpoint the exact field that is the wrong type and give a concrete patch you can use (either a change in your code or a small shim to normalize the event before serialization).
Would you like me to walk you through adding the small log inside _send_client_event, or do you prefer to try audio=None first?
, with interactive elementsincalculable-garage-37123
03/18/2026, 11:38 AMtall-airline-16756
03/18/2026, 11:38 AM.audio attribute is a plain string, causing the Pydantic serialization error and preventing downstream input handling.
• Because another agent works, this is probably specific to the failing agent’s event construction, plugin, or pipeline output.
To narrow root cause — please provide two quick pieces of info 1) Details about the working agent
• Which LiveKit packages/version does the working agent use? (Run pip freeze | grep livekit in that agent’s environment.)
• Does it use different TTS/STT or plugin(s) (e.g., ElevenLabs vs. Silero, Deepgram vs. AssemblyAI)? Name any plugins configured for that agent.
2) A short event dump or log from the failing agent right before serialization
• If you can, add a very small log in your environment at/near the serialization call inside client_events._send_client_event (line around event.model_dump_json()), or log from your wrapper prior to calling session.say(). Paste the output here. Specifically, we want:
◦ type(event)
◦ event.model_dump() or event.dict
If you can’t edit library code, logging the greeting variable type/value right before session.say() is still useful:
greeting = f"Hello, Am I talking to {name}?"
self._session_logger.log_info("greeting_type", type(greeting), repr(greeting))
await self.session.say(text=greeting, allow_interruptions=False)
Tests to run now (pick one to try)
• Compare plugins/config: If the working agent uses a different TTS/STT plugin, that could produce a different event shape. Tell me which plugin differs.
• Try explicit audio field: Call session.say(text=greeting, audio=None, allow_interruptions=False) to see if explicitly providing an audio attribute avoids the serializer error.
• Swap agents’ configs: If possible, run the failing agent with the working agent’s plugin list (or vice versa) to see if the problem follows a plugin.
What I’ll do once you share the above
• If you provide the event dump (type + model_dump/*dict*), I will point exactly which attribute is the wrong type and give the exact code to normalize it (a small shim or change to your call).
• If you provide the working agent’s package/plugin differences, I’ll highlight which component likely changes the event shape and show how to adapt.
• If the explicit audio=None test changes behavior, I’ll show a safe short-term patch you can apply.
Would you like to:
• Paste the event dump (best), or
• Tell me the working agent’s plugin list and versions, or
• Try audio=None and paste that log result?
I’ll stay with you and provide the exact fix once you paste whichever output you can get.
, with interactive elementsincalculable-garage-37123
03/18/2026, 11:40 AMtall-airline-16756
03/18/2026, 11:41 AMevent.model_dump_json() in client_events._send_client_event). We want:
◦ type(event)
◦ event.model_dump() or event.dict
If you cannot modify the library, paste the log output from adding a debug just before your session.say() call showing the greeting type/value (you already logged the greeting text — now include type):
self._session_logger.log_info("greeting_type", type(greeting), repr(greeting))
Three very small tests you can try now (pick one and tell me the result) 1) Explicit audio attribute (quickest to try)
• Change the call to:
await self.session.say(text=greeting, audio=None, allow_interruptions=False)
• Tell me whether the serialization error still appears.
2) Downgrade to confirm regression
• Temporarily reinstall the working agent version:
pip install livekit-agents==1.2.13
• If the error disappears, we confirm a breaking change in newer releases.
3) Add narrow debug at serializer
• If you can edit site-packages temporarily, add these logs at the top of client_events._send_client_event (right before event.model_dump_json()):
◦ print(type(event))
◦ print(event.model_dump()) # or event.dict
• Paste that output here.
Why each test helps
• (1) If audio=None fixes it, the serializer expects an audio attribute and the library no longer auto-wraps strings. We can add a small shim in your code to always provide an audio attribute.
• (2) If rollback fixes it, we have a stable workaround (pin to 1.2.13) while we craft a small patch.
• (3) Seeing the event shape gives me the exact field that is the wrong type and I can provide the exact code to normalize it.
Short-term workaround option
• If you need an immediate restore of functionality, pin to the older working version:
pip install livekit-agents==1.2.13 This is safe while we identify the exact change and produce a minimal code fix.
What I’ll do for you next
• If you try (1) or (2), tell me the result and I’ll give the exact code change or the pin command.
• If you can paste the event dump (from (3)), I will point to the specific attribute and provide the exact code to convert it into the required structure (a tiny shim you can add to your agent).
Would you like to try the audio=None call first, or paste the event dump from inside _send_client_event? I’ll guide you step‑by‑step.
, with interactive elementsincalculable-garage-37123
03/18/2026, 11:44 AMtall-airline-16756
03/18/2026, 11:44 AM.audio) but one or more items are plain strings.
• That explains why audio plays (TTS worked) but serialization fails when building a structured representation of the chat context for clients/LLM: playback and event serialization are different code paths.
• This mismatch surfaced after the package upgrade because newer code enforces that shape when serializing.
What I need to confirm
• Do you (or any code path you use) append raw strings into the chat context or instructions? Common places to check:
◦ Any call like session.context.set_instructions(...), session.chat_context.append(...), or direct manipulations of chat context where you pass plain strings.
◦ Custom tool outputs or pipeline nodes that return strings and are then added into the chat context without wrapping.
Small, targeted fixes you can try now 1) Convert strings to an Instruction-like object before adding them
• Wherever you add instructions/messages to the chat context, wrap them in the proper model rather than adding a bare string. Example (adapt to your codebase / imports):
from livekit.agents.llm.chat_context import InstructionMessage # adjust import if different
instr = InstructionMessage(text="Your instruction here", audio=None)
session.chat_context.append(instr)
If InstructionMessage has a different constructor in your version, use the fields required (ensure an audio attribute exists — can be None if no audio).
2) Normalize existing context when serializing (short shim)
• If you cannot find the insertion point quickly, add a small normalization before serialization (or before you call the API that triggers serialization). Example pseudo-shim:
def normalize_item(v):
if isinstance(v, str):
# build minimal object with an audio attr
return InstructionMessage(text=v, audio=None)
return v
# before serialization / before session close
session.chat_context = [normalize_item(v) for v in session.chat_context]
3) Quick debugging to find where the string is introduced
• Add logging at places you modify the chat context, or temporarily log the chat_context contents just before the error path (e.g., right before AgentSession aclose or where audio recognition bounces EOU). Print types and reprs to find which entry is a str:
for i, item in enumerate(session.chat_context):
logger.info("ctx_item", i=i, type=type(item), repr=repr(item))
Immediate workaround options
• If you need fast recovery, roll back to the working package version you mentioned:
pip install livekit-agents==1.2.13 That will restore behavior until you convert the string entries to the expected object shape.
• Alternatively, apply the small normalization shim above to convert any string entries to Instruction-like objects before serialization.
What I can do next
• If you paste any code that modifies the chat context (calls to set_instructions, append, or any custom tool output that gets added), I’ll point out exactly where to change it and give the exact code snippet for your version.
• If you’d prefer, paste a small dump of session.chat_context (types and reprs) and I’ll mark which items are wrong and show the exact conversion to the expected model.
Would you like me to:
• Provide the exact import/constructor for InstructionMessage for your installed version (I can look it up if you confirm you want that), or
• Give the minimal shim to normalize current chat context items into the correct model so you can patch quickly?
Tell me which you prefer and paste any small snippet that adds to chat context and I’ll give the exact patch.
, with interactive elements