What is wrong
parse_session crashes with TypeError: can't compare offset-naive and offset-aware datetimes whenever a transcript contains at least one Agent delegation with a usable ISO timestamp and at least one without.
Reproduce (this is a real run against the current main):
import json, pathlib
from agentrace.parse import parse_session
p = pathlib.Path("/tmp/t.jsonl")
p.write_text("\n".join(json.dumps(x) for x in [
{"timestamp": "2026-07-16T12:00:00.000Z",
"message": {"content": [{"type": "tool_use", "id": "a", "name": "Agent", "input": {"prompt": "p"}}]}},
{"message": {"content": [{"type": "tool_use", "id": "b", "name": "Agent", "input": {"prompt": "q"}}]}},
]))
parse_session(p)
# TypeError: can't compare offset-naive and offset-aware datetimes
Why it matters
The whole premise in parse.py is that you can point agentrace at a transcript you did not plan to trace and it will just work. A single record with a missing, malformed, or non-ISO timestamp makes the entire session unreadable, and the traceback gives no hint that a timestamp is the cause. _ts (agentrace/parse.py lines 73-79) already returns None on bad input by design, so the failure is downstream of a deliberate choice to be tolerant.
Where it is
agentrace/parse.py line 159:
runs.sort(key=lambda r: (r.started_at or datetime.min.replace(tzinfo=None), r.tool_use_id))
_ts returns timezone-aware datetimes for real Claude Code timestamps (they end in Z), but the fallback here is explicitly naive, so the two are never comparable.
Suggested fix
- In
agentrace/parse.py, make the sort key total by never mixing naive and aware values. The simplest correct version is a two-part key that puts unknown-start runs in a fixed position, for example sort on (r.started_at is None, r.started_at or <a fixed aware minimum>, r.tool_use_id), or sort with datetime.min.replace(tzinfo=timezone.utc) as the fallback and import timezone.
- Decide and state in a short comment whether timestamp-less runs sort first or last. First reads better: they are usually the in-flight ones you opened the tool to look at.
- Add a test in
tests/test_agentrace.py next to test_run_without_result_still_parses, for example test_mixed_missing_timestamps_still_parse, using two tool_use records where only one carries a timestamp. It should fail before the fix.
Note that the existing tests do not catch this because every fixture either has timestamps on all records or on none.
If you want to take this one, comment below and it is yours. I usually reply within a day.
What is wrong
parse_sessioncrashes withTypeError: can't compare offset-naive and offset-aware datetimeswhenever a transcript contains at least one Agent delegation with a usable ISO timestamp and at least one without.Reproduce (this is a real run against the current
main):Why it matters
The whole premise in
parse.pyis that you can point agentrace at a transcript you did not plan to trace and it will just work. A single record with a missing, malformed, or non-ISOtimestampmakes the entire session unreadable, and the traceback gives no hint that a timestamp is the cause._ts(agentrace/parse.pylines 73-79) already returnsNoneon bad input by design, so the failure is downstream of a deliberate choice to be tolerant.Where it is
agentrace/parse.pyline 159:_tsreturns timezone-aware datetimes for real Claude Code timestamps (they end inZ), but the fallback here is explicitly naive, so the two are never comparable.Suggested fix
agentrace/parse.py, make the sort key total by never mixing naive and aware values. The simplest correct version is a two-part key that puts unknown-start runs in a fixed position, for example sort on(r.started_at is None, r.started_at or <a fixed aware minimum>, r.tool_use_id), or sort withdatetime.min.replace(tzinfo=timezone.utc)as the fallback and importtimezone.tests/test_agentrace.pynext totest_run_without_result_still_parses, for exampletest_mixed_missing_timestamps_still_parse, using twotool_userecords where only one carries atimestamp. It should fail before the fix.Note that the existing tests do not catch this because every fixture either has timestamps on all records or on none.
If you want to take this one, comment below and it is yours. I usually reply within a day.