Skip to content

fix: one unprobeable .jsonl no longer blanks the whole usage dashboard - #79

Merged
Carl723000 merged 2 commits into
ClaudeCodeUsage:mainfrom
ptweezy:fix/timestamp-probe-fail-soft
Aug 1, 2026
Merged

Carl723000 merged 2 commits into
ClaudeCodeUsage:mainfrom
ptweezy:fix/timestamp-probe-fail-soft

Conversation

@ptweezy

@ptweezy ptweezy commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

大家好

Problem

sortUsageFilesByEarliestTimestamp maps readEarliestTimestamp over every
discovered .jsonl via mapWithConcurrency, with no per-file error handling.
readEarliestTimestamp throws TimestampProbeLimitError when a file has more
than 1 MiB of leading lines that carry no timestamp field (covered by the
existing "timestamp probing is bounded when no valid timestamp exists" test).

That rejection is unhandled, so Promise.all rejects, the error unwinds out of
loadUsageRecords, and the outer catch returns { records: [] } with
filesFailed = Math.max(filesFailed, 1). A single such file empties the entire
file-based dashboard on every refresh. Diagnostics report failed=1 with
bytes=0. The API quota path is separate and keeps working, so only the
usage/history panel goes blank.

The file type that triggers this in normal use is a workflow journal.jsonl:
its records contain type, key, result, and agentId, never a
timestamp, and a workflow run with a few hundred sub-agents produces a
journal.jsonl over 1 MiB.

Origin

This surfaced from Claude Code's Workflow feature (multi-agent orchestration).
Each run writes a journal at
~/.claude/projects/<project>/<session>/subagents/workflows/<workflow-id>/journal.jsonl,
one line per sub-agent lifecycle event: a started line and a result line
per agent, each holding type, key, result, and agentId and no
timestamp. The result values make some lines large. A single run that
fanned out to roughly two hundred sub-agents produced a 1.32 MB, 402-line
journal, over the 1 MiB probe limit. From then on every refresh returned empty
records (failed=1, bytes=0) and the dashboard stayed blank while the
status-bar quota kept updating, which presented as a rendering fault rather
than a load abort.

Reproduction

  1. Create a .jsonl under ~/.claude/projects/<project>/ whose first 1 MiB
    contains no line with a timestamp field:

    node -e 'const fs=require("fs"),os=require("os"),p=require("path");const d=p.join(os.homedir(),".claude","projects","repro");fs.mkdirSync(d,{recursive:true});fs.writeFileSync(p.join(d,"journal.jsonl"),`{"type":"result","key":"k","agentId":"a"}\n`.repeat(40000))'
    

    Equivalently, run any workflow whose
    subagents/workflows/<id>/journal.jsonl grows past 1 MiB.

  2. Open the extension or trigger a refresh.

  3. The dashboard is empty. Show Diagnostic Logs reports failed=1 and bytes=0
    on every refresh, while the status-bar quota continues to update.

With the fix, the same setup loads the remaining files normally and the
dashboard populates; the oversized file is skipped for ordering.

Fix

Catch the per-file probe failure in sortUsageFilesByEarliestTimestamp and fall
back to timestampMs: 0, so the file sorts by discovery order — the same value
readEarliestTimestamp already returns for a small file that has no timestamp.
One unprobeable or transiently unreadable file no longer aborts the batch, and
the file is still passed to the main reader.

readEarliestTimestamp and its guard test are unchanged.

Test

Adds "a single unprobeable file does not abort ordering the rest" to
src/test/claudeUsageFiles.test.ts: a >1 MiB no-timestamp journal.jsonl
beside a normal file. It asserts readEarliestTimestamp still rejects on the
journal, and that sortUsageFilesByEarliestTimestamp resolves and returns both
files.

CHANGELOG.md is updated. package.json version is left unchanged per
CONTRIBUTING.

谢谢

sortUsageFilesByEarliestTimestamp mapped readEarliestTimestamp over every
file with no per-file error handling. A file that trips the probe's 1 MiB
no-timestamp guard (TimestampProbeLimitError), such as a large workflow
journal.jsonl, rejected the whole batch, so loadUsageRecords returned empty
records and the dashboard blanked on every refresh (failed=1, bytes=0).

Catch the per-file failure and fall back to timestampMs 0 so the file sorts
by discovery order, matching the existing small-no-timestamp behavior. The
rest of the load proceeds and the file still reaches the main reader.
readEarliestTimestamp and its test are unchanged. Adds a regression test.
@github-actions github-actions Bot added the fix Patch — bug fix label Jul 21, 2026
@github-actions

Copy link
Copy Markdown

🤖 Automated first-pass review

**TL;DR** Correct, well-structured fix that handles the degenerate case cleanly. Follows project conventions (no new dependencies, CHANGELOG updated, test added). Merge-ready.

Analysis

  • Correctness: The catch block returns { timestampMs: 0, bytesRead: 0 } for any file whose probe throws, matching the existing fallback used for small no-timestamp files. This is exactly what readEarliestTimestamp already returns in that path, so sorting and downstream processing are consistent. The test verifies both that the probe still rejects and that the ordering resolves with both files. No correctness risk.

  • Convention / i18n / CHANGELOG:

    • CHANGELOG entry is clear, follows Keep a Changelog, and is placed under the existing ### Fixed section.
    • No user-facing strings added, so i18n is unaffected.
    • No new runtime dependencies.
    • package.json version left unchanged as required by CONTRIBUTING.
    • Test uses node:test and node:assert as prescribed.
  • Merge-readiness: The diff is focused and minimal. The only minor note is that the test relies on a fixture() function that is not visible in this diff—it is presumably defined earlier in the same test file. If that assumption holds (likely, given the existing test structure), the PR is fully ready.

**Suggested


🤖 Generated by DeepSeek as an automated first pass — not a maintainer decision.

Keep both the timestamp-probe and Opus 5 changelog entries while updating the original contributor branch.

Co-authored-by: OpenAI Codex <215057067+openai-codex[bot]@users.noreply.github.com>
@Carl723000 Carl723000 added the patch Patch bump label Aug 1, 2026
@Carl723000
Carl723000 merged commit 231a30b into ClaudeCodeUsage:main Aug 1, 2026
2 checks passed
@ptweezy
ptweezy deleted the fix/timestamp-probe-fail-soft branch August 1, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Patch — bug fix patch Patch bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants