Repository navigation
Session resume fails when masked code-change metrics make session.shutdown counters strings #5023
Description
Describe the bug
A persisted Copilot CLI session can become permanently unresumable when code-change counters in a file-editing tool's toolTelemetry.metrics are stored as masked strings instead of numbers.
Observed behavior on a programmatic CLI session:
- A file-editing tool completes with nonnegative integer
linesAdded/linesRemovedmetrics. - The post-tool hook receives those integer values and reports that it did not modify the result.
- The persisted
tool.execution_completeevent contains a string such as"******"for one or both counters. - The session usage tracker aggregates the value with
+=without validating its type. JavaScript then concatenates the string into the session total. session.shutdown.data.codeChanges.linesAddedorlinesRemovedis persisted as a string.- The next
session.resumerejectsevents.jsonlbecauseShutdownCodeChangesrequires an integer (expected i64).
The session's conversation and tool results remain present, but the entire session can no longer be resumed because of diagnostic usage metadata.
Affected versions
@github/copilot: 1.0.73 (package build commit98003c0)@github/copilot-sdk: 1.0.7- Runtime: Linux container, Node.js 20
Why this appears to happen
The external tool result contract permits opaque JSON under toolTelemetry. The shutdown event contract is stricter and requires nonnegative integers for codeChanges.linesAdded and linesRemoved.
The 1.0.73 runtime's usage aggregation effectively performs:
aggregate.linesAdded += toolTelemetry.metrics.linesAdded ?? 0;
aggregate.linesRemoved += toolTelemetry.metrics.linesRemoved ?? 0;If a persisted tool event contains a masked string, numeric addition becomes string concatenation. The resulting shutdown record violates the runtime's own resume schema.
The exact component that replaces the original integer with the masked string appears to be between post-tool-hook completion and persisted tool.execution_complete event creation. The tool result itself and the unmodified post-tool-hook input contain integers.
Expected behavior
linesAddedandlinesRemovedremain nonnegative integers throughout tool-event persistence.- Invalid diagnostic metrics never make the conversation unresumable.
- Resume tolerates or repairs malformed diagnostic-only usage fields rather than rejecting the complete session.
Suggested fixes
- Validate code-change counters before writing
tool.execution_complete. - In usage aggregation, add values only when
Number.isSafeInteger(value) && value >= 0. - During event replay, ignore malformed code-change metrics instead of concatenating them.
- Before writing
session.shutdown, assert that aggregate counters satisfyShutdownCodeChanges. - Add a backward-compatible repair path for already persisted sessions, treating unrecoverable masked counters as zero or recomputing them from valid events.
- Consider skip-and-warn behavior for schema-invalid diagnostic fields so one metric cannot invalidate a complete session.
Workaround
With the CLI stopped, back up events.jsonl, then atomically sanitize both locations while preserving one JSON object per LF-terminated line:
- In
tool.execution_complete, replace non-integer or negativetoolTelemetry.metrics.linesAdded/linesRemovedwith0(or remove those metric keys). - In
session.shutdown, replace invalidcodeChanges.linesAdded/linesRemovedwith0, or recompute them from valid tool events.
Both locations must be repaired; fixing only the shutdown record can allow replay of an earlier malformed tool event to poison a later shutdown again.
Related issues
This appears to be another writer-versus-validator mismatch in the same family as:
- data.totalPremiumRequests was returned as float, while an int is expected, causing corruption of a session file #3432 - shutdown metric written as a float while the schema required an integer
- Session unloadable when Windows shell exits with negative exit code --
data.kind.exitCode: Number must be greater than or equal to 0#3454 - valid Windows exit code rejected by an overly strict schema - Session resume fails when session.compaction_complete writes negative tokensRemoved (schema requires >= 0) #3598 - negative
tokensRemovedmade sessions unresumable - Usage data is incorrect when sessions are resumed #524 - resumed-session usage metrics were inconsistent
No raw session logs, user content, or internal identifiers are included in this report.
Activity
dewanymca commentedon Oct 1, 2026
Thanks for triaging. what is the ETA for the fix here? We are ready to rollout but this is causing issues.
patniko commentedon Oct 26, 2026
Thanks for the report. We've shipped fixes in this area since this was filed, and we believe this may now be resolved. Could you retest on the latest release (Copilot CLI v1.0.103) and let us know whether you still see it? If we don't hear back in a couple of weeks, we may close this issue — you can always reopen it.
Triaged as part of a Copilot SDK backlog review, with help from GitHub Copilot.