Skip to content

Bug: parse_session crashes on a transcript where only some Agent runs have timestamps #3

Description

@royalpinto007

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

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions