Summary
list_sessions() returns created_at=None for sessions whose first JSONL record does not contain a timestamp field, even though later records in the same file do.
Root cause
In _internal/sessions.py, _parse_session_lite() (around line 461) calls:
first_timestamp = _extract_json_string_field(first_line, "timestamp")
_extract_json_string_field does a raw substring search for "timestamp":" anywhere in first_line. This means:
- Sessions whose first record is
permission-mode (e.g. {"type":"permission-mode","permissionMode":"acceptEdits","sessionId":"..."}) have no timestamp anywhere in that line → created_at stays None.
- Sessions whose first record is
file-history-snapshot incidentally get a valid created_at because the snapshot embeds a nested timestamp: "snapshot":{"messageId":"...","timestamp":"2026-04-27T00:08:..."} — the raw search matches the nested field, not a top-level one.
So created_at is populated based on an accidental nested-field match in one record type, and absent for another, rather than reliably reflecting the session start time.
Steps to reproduce
- Open a Claude Code session that begins with a
permission-mode record as the first line in its JSONL file.
- Call
list_sessions().
- Observe
session.created_at is None for that session.
You can verify the first-line type with:
import json
with open(f"~/.claude/projects/.../SESSION_ID.jsonl") as f:
print(json.loads(f.readline()).get("type"))
# "permission-mode" → created_at will be None
# "file-history-snapshot" → created_at may be incidentally populated via nested timestamp
Expected behavior
created_at should reliably reflect the timestamp of the first user interaction (or session start), regardless of which record type appears first in the file.
Suggested fix
Instead of reading only first_line, scan through the lines in head until a record with a top-level timestamp field is found — or specifically look for the first user or assistant type record. Alternatively, use the top-level timestamp field and skip records that lack it, rather than matching incidental nested occurrences.
Environment
claude-agent-sdk version: 0.1.63
- Python: 3.12
Summary
list_sessions()returnscreated_at=Nonefor sessions whose first JSONL record does not contain atimestampfield, even though later records in the same file do.Root cause
In
_internal/sessions.py,_parse_session_lite()(around line 461) calls:_extract_json_string_fielddoes a raw substring search for"timestamp":"anywhere infirst_line. This means:permission-mode(e.g.{"type":"permission-mode","permissionMode":"acceptEdits","sessionId":"..."}) have notimestampanywhere in that line →created_atstaysNone.file-history-snapshotincidentally get a validcreated_atbecause the snapshot embeds a nested timestamp:"snapshot":{"messageId":"...","timestamp":"2026-04-27T00:08:..."}— the raw search matches the nested field, not a top-level one.So
created_atis populated based on an accidental nested-field match in one record type, and absent for another, rather than reliably reflecting the session start time.Steps to reproduce
permission-moderecord as the first line in its JSONL file.list_sessions().session.created_at is Nonefor that session.You can verify the first-line type with:
Expected behavior
created_atshould reliably reflect the timestamp of the first user interaction (or session start), regardless of which record type appears first in the file.Suggested fix
Instead of reading only
first_line, scan through the lines inheaduntil a record with a top-leveltimestampfield is found — or specifically look for the firstuserorassistanttype record. Alternatively, use the top-leveltimestampfield and skip records that lack it, rather than matching incidental nested occurrences.Environment
claude-agent-sdkversion: 0.1.63