Repository navigation
fix(codex): guard truncated type fields from panicking the parser - #2034
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | ce7707f | Commit Preview URL Branch Preview URL |
Nov 07 2026, 12:45 AM |
bvolpato
left a comment
There was a problem hiding this comment.
Reviewed at 9a93a8a. No correctness findings. The bounds check covers both paths that advance the scanner past EOF, and the regression verifies that malformed records are skipped without losing valid surrounding usage.
I verified that this PR's entire source tree matches the patch I tested for #2033. The regression failed before the fix and passed afterward. Full Rust workspace tests, Node tests, Rust formatting, and Codex adapter Clippy passed. The patched release binary also completed the full offline report against the unchanged logs that reproduced the original crash.
Approving the code. Hosted CI and autofix.ci still show action_required with no jobs executed; those should run before merging. The Nix formatter and oxlint were unavailable locally, so their checks remain unverified.
|
/codesmith prove it |
|
Your payment method failed for a Blacksmith invoice. [code]smith is paused until it is resolved. Update your payment method on the billing page. |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
* docs(skills): credit issue reporters and reply after merging Squash merges of #2050, #2051 and #2034 left out the reporters whose issues drove the fixes, and #2004 and #1987 got no reply after the contributor pinged. The create-pr skill now covers both steps at merge time, so they are no longer left to memory. * docs(skills): say how to add the reporter trailer and where to reply for a bare branch * docs(skills): name the squash body flag, noreply lookup and pending release * docs(skills): mention the next release only for shipped changes * docs(skills): report the shipped release when it already exists
* docs(skills): credit issue reporters and reply after merging Squash merges of #2050, #2051 and #2034 left out the reporters whose issues drove the fixes, and #2004 and #1987 got no reply after the contributor pinged. The create-pr skill now covers both steps at merge time, so they are no longer left to memory. * fix(claude): show model breakdowns for session --id `ccusage claude session --id <ID>` ignored `--breakdown`, and its JSON had no `modelBreakdowns`. The lookup path summed cost and tokens by hand instead of building the `UsageSummary` that the session list builds with `SessionAccumulator`, so it never had per-model data and never reached the shared table renderer that draws breakdown rows. Build the looked-up session through the same `SessionAccumulator` and render the table with the shared `print_usage_table`, matching how `codex session --id` reuses its session table. `--breakdown` now adds per-model rows, and the JSON keeps its existing fields while adding `modelsUsed` and `modelBreakdowns` (including `storedCost` and `missingPricing` where they apply). The text summary with a separate "Total Entries" line is replaced by the standard session table. Codex already honors `--breakdown` for `--id` and the top-level `ccusage session --id` routes to this Claude path, so no other agent needed a change. Co-authored-by: fdarian <[email protected]> * docs(session): document model breakdowns for claude session --id Describe the table and JSON shape of `ccusage claude session --id` now that it shares the session table and emits `modelBreakdowns`, and note that its breakdown entries mark unpriced models. * Revert "docs(skills): credit issue reporters and reply after merging" This reverts commit 3a33754. --------- Co-authored-by: fdarian <[email protected]>
The squash merge of #2034 missed a Co-authored-by trailer for the reporter whose issue (#2033) and reproduction drove the fix. This empty commit records that credit. Co-authored-by: Bruno Volpato <[email protected]>
Upstream tip: 660e07c (2026-11-13, chore(pricing): update models.dev snapshot) Previous fork base: 30b653f (the upstream commit this fork was synced to) Synced 100 upstream commits on top of 30b653f: 53 automated pricing snapshot refreshes, 23 dependency bumps, 2 releases, and: 3541115 feat(cline): add extension and CLI usage adapter (ccusage#1977) 5e5c475 fix(antigravity): report real model names instead of placeholders (ccusage#2071) e39ed83 fix(claude): keep the cache TTL split when deduping equal copies (ccusage#2060) c17c591 feat(adapter): report 1h cache writes in JSON model breakdowns (ccusage#2059) a06f4bc perf(claude): halve `ccusage claude` report time (ccusage#2058) de43952 fix(claude): show model breakdowns for session --id (ccusage#2057) 5f31039 fix(all): count only in-window Claude usage in unified session reports (ccusage#2052) e4f0ea9 fix(codex): count spawned subagent requests stamped at the fork instant (ccusage#2051) b85b28f fix(opencode): count usage from completed v2 compaction rows (ccusage#2050) 00fead0 fix(antigravity): deduplicate unkeyed mirror usage (ccusage#2027) 2248106 fix(opencode): exclude Claude Agent turns by default (ccusage#2022) 4fb1c0d fix(codex): guard truncated type fields from panicking the parser (ccusage#2034) 86707db build(perf): make the PR performance comparison catch real regressions (ccusage#2061) 686a1a8 ci: support a merge queue on main (ccusage#2062) Fork wins kept: the Codex optimized scanner with its fork-replay instant, the Antigravity model resolver, the OpenCode retained-ledger cache with its per-namespace rows, the SQLite on-disk cache, the table renderer, the fork CI and tag-only release workflow, and the exact `=` dependency pins. Hand-resolved conflicts: rust/adapters/claude/src/lib.rs: the fork's DedupedEntries copy pairs stay and take upstream's carries_more_usage_detail tiebreak (speed rank, then a cache TTL split); main_thread_session_days reads the recorded session of each copy. rust/adapters/opencode/{loader,parser}.rs: the fork's retain_via_ledger stays beside upstream's v2 compaction scan; SessionMessageKind and MessageRowColumns carry the row type through the five-value scan. rust/adapters/codex/{replay,parser}.rs: open_rollout_reader_with_capacity and CodexForkReplay both land in the shared parser state. rust/crates/ccusage-core/src/{cache,pricing}.rs: the opencode-db-compaction namespace joins the ledger namespaces; the fork's embedded pricing loader and OnceLock path stay. rust/crates/ccusage/src/cli/timezone.rs: Cline joins the shared-args arm, the ClearCache arm stays unreachable from the parser. rust/Cargo.toml: the fork's exact `=` pins stay; jiff 0.2.41, schemars 1.2.2, serde 1.0.229, smallvec 1.16.5, toml 1.2.1. .github/workflows/{ci,release}.yaml: the fork's design is kept, including its own release flow. Upstream's merge-queue, tagpr and pkg.pr.new jobs need scripts this fork deleted, so they are not taken; the two save-nix-cache inputs upstream passes to the native-package actions are dropped because the fork's composite actions declare no such input. packages/ccusage-*/package.json (6 files), the contribution-gate scripts, sponsors.md, blacksmith.png and rust/adapters/claude/src/daily.rs stay deleted; the two Blacksmith SVG logos upstream added are not taken. Docs: the agent lists take upstream's Cline addition but keep this fork's `pi` name, because the CLI subcommand is still `pi`; upstream renamed the docs to `pi-agent` without renaming the command. Snapshots regenerated for the fork table renderer: the Cline adapter, CLI and unified reports, codex issue_2046, opencode compaction, claude session --id and the config schema (new Cline section). Validation: cargo test --workspace --offline 1297 passed, 0 failed; cargo clippy --workspace --all-targets clean; rustfmt --check clean. Version: take upstream's 20.0.50 in package.json, apps/ccusage/package.json and docs/package.json; the Rust workspace keeps version 0.0.0. DO NOT push a v20.0.50 tag from this fork: release.yaml would publish fork bytes under upstream identity.
References #2033:
codex_line_type_flagsinrust/adapters/codex/src/parser.rsadvancedstarttoline.len() + 1on truncated"type"fields (missing value or opening quote) and then slicedline[start..], panicking the whole report under thepanic = "abort"release profile. Guarded the scan loop withstart < line.len()so malformed lines fall through to the existing JSON skip path and valid surrounding usage is still counted.Added
skips_truncated_type_fields_without_losing_valid_usageregression test inrust/adapters/codex/src/loader.rscovering{"type" :, whitespace-only tails, empty values, and truncated nestedpayload.typefields around a validtoken_countevent.Tests: new regression test panicked before the fix (
range start index 11 out of range for slice of length 10atparser.rs:739) and passes after;cargo test -p ccusage -p ccusage-adapter-codex --features ccusage/fetch-litellm-pricing --libpasses (162 passed);cargo fmt --all -- --checkclean;cargo clippy -p ccusage -p ccusage-adapter-codex --all-targets --features ccusage/fetch-litellm-pricing -- -D warningsclean. Changes left uncommitted in the working tree.Closes #2033
Summary by cubic
Fixes the Codex adapter parser panicking on truncated
"type"fields in session lines. In release builds withpanic = "abort", a malformed field (missing value or opening quote) advanced the scan index past the end of the line and sliced past the buffer, crashing the whole report. The scan loop is now guarded so malformed lines fall through to the existing JSON skip path while validtoken_countusage on surrounding lines is still recorded.Adds a regression test covering truncated
"type"fields with missing values, whitespace-only tails, empty values, and truncated nestedpayload.typefields, verifying they are skipped without losing valid usage. Closes #2033.Written for commit ce7707f. Summary will update on new commits.