diff --git a/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py b/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py index f655c5611..e0310abf3 100644 --- a/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py +++ b/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py @@ -909,6 +909,23 @@ class TraceCollectionListener(BaseEventListener): if event_type == "llm_call_completed": return _serialize_for_trace(event) + # Error events need agent/task identification extracted before generic + # serialization strips them (agent/task are in TRACE_EXCLUDE_FIELDS) + if event_type == "agent_execution_error": + event_data = _serialize_for_trace(event) + if event.agent: + event_data["agent_role"] = getattr(event.agent, "role", None) + event_data["agent_id"] = str(getattr(event.agent, "id", "")) + return event_data + if event_type == "task_failed": + event_data = _serialize_for_trace(event) + if event.task: + event_data["task_name"] = getattr(event.task, "name", None) or getattr( + event.task, "description", None + ) + event_data["task_id"] = str(getattr(event.task, "id", "")) + return event_data + # For all other events, use lightweight serialization return _serialize_for_trace(event) diff --git a/lib/crewai/src/crewai/utilities/serialization.py b/lib/crewai/src/crewai/utilities/serialization.py index 0cb48dade..cc6f55cab 100644 --- a/lib/crewai/src/crewai/utilities/serialization.py +++ b/lib/crewai/src/crewai/utilities/serialization.py @@ -109,12 +109,12 @@ def to_serializable( return repr(obj) # Handle regular classes with __dict__ (non-Pydantic) + # Note: Don't propagate exclude to recursive calls, matching Pydantic fallback behavior if hasattr(obj, "__dict__"): try: return { _to_serializable_key(k): to_serializable( v, - exclude=exclude, max_depth=max_depth, _current_depth=_current_depth + 1, _ancestors=new_ancestors,