Skip to content

Session fails to load: strict schema validation rejects legacy session.compaction_complete events after upgrade to 1.0.35-3 #2899

@ericsciple

Description

@ericsciple

Session fails to load: strict schema validation rejects older session.compaction_complete events

Summary

After updating to CLI 1.0.35-3, copilot --resume=<id> fails to load any session whose events.jsonl contains a session.compaction_complete event written by an earlier CLI version. The parser rejects the event instead of migrating/tolerating legacy shapes, which permanently bricks otherwise healthy sessions.

Version

  • CLI: GitHub Copilot CLI 1.0.35-3
  • OS: macOS (Darwin, arm64)
  • Install: Homebrew cask (/opt/homebrew/bin/copilot)
  • Pkg bundle in use: ~/.copilot/pkg/universal/1.0.35-3/sdk/index.js

Impact

  • Many of my local sessions were unloadable after the upgrade (8 of 35 on this machine). All had valid, cleanly-shutdown events.jsonl files; only the compaction events were in the old shape.
  • There is no UI recovery path: copilot --resume=<id> surfaces only No session or task matched '<id>'. The real parser error is only visible in ~/.copilot/logs/process-*.log.
  • Nothing the user does (including ordinary actions like renaming a session summary) causes this — it's purely the CLI tightening the schema between versions.

Reproduction

  1. Use a CLI version that writes compaction events with the old shape (keys under data.compactionTokensUsed are input, output, cachedInput).
  2. Trigger an auto-compaction so at least one session.compaction_complete event lands in events.jsonl.
  3. Upgrade to 1.0.35-3.
  4. Run copilot --resume=<that-session-id>.

Expected: session loads (with or without a migration).
Actual: session fails to load; CLI reports "No session or task matched".

Log excerpt

[ERROR] Failed to parse session c00dcf1c-6727-4487-a3cf-c240cd486191:
  Error: Failed to read JSONL from .../events.jsonl:
  Error: Invalid event at line 785: data.compactionTokensUsed.inputTokens: Required.
  Event: {"type":"session.compaction_complete","data":{"success":true,"preCompactionTokens":135195,...
[ERROR] No session or task matched 'c00dcf1c-6727-4487-a3cf-c240cd486191'

Root cause

The session.compaction_complete schema changed key names and was tightened from optional to required. In ~/.copilot/pkg/universal/1.0.35-3/sdk/index.js:

zjo = be({
  inputTokens:      At().describe("Input tokens consumed by the compaction LLM call"),
  outputTokens:     At().describe("Output tokens produced by the compaction LLM call"),
  cacheReadTokens:  At().describe("Cached input tokens reused in the compaction LLM call"),
  cacheWriteTokens: At().describe("Tokens written to prompt cache in the compaction LLM call"),
  copilotUsage:     d9r.optional(),
  duration:         At().optional(),
  model:            V().optional(),
})

For comparison, the older bundled d.ts under ~/.copilot/pkg/universal/1.0.28/copilot-sdk/generated/session-events.d.ts still describes the legacy keys and marks compactionTokensUsed itself as optional:

compactionTokensUsed?: {
  input: number;
  output: number;
  cachedInput: number;
}

So legacy events look like:

{"compactionTokensUsed": {"input": 169241, "output": 3880, "cachedInput": 164955}}

…and the new parser rejects them because inputTokens is missing.

Suggested fixes (pick any)

  1. Version / migrate legacy events on read. When parsing session.compaction_complete with old keys (input/output/cachedInput), map them to (inputTokens/outputTokens/cacheReadTokens) and default cacheWriteTokens to 0. This is a one-line normalization and preserves history.
  2. Relax the schema. Make inputTokens/outputTokens/cacheReadTokens/cacheWriteTokens optional (they're telemetry anyway), or accept both legacy and new key shapes via a union.
  3. Fail soft. If a single event fails validation, skip it (log a warning) rather than aborting the entire session load. The current behavior is a permanent data-loss risk whenever the schema evolves.
  4. Surface the real error in the UI. Today users see only "No session or task matched", which suggests the session is missing; the actual parse error is log-only. At minimum print the underlying cause and the offending line.

Manual workaround (for the record)

Patching the offending events repairs the session. Back up first:

python3 - <<'PY'
import json, os, shutil
paths = [
  "/Users/<me>/.copilot/session-state/<id>/events.jsonl",
]
for p in paths:
    bak = p + ".bak"
    if not os.path.exists(bak):
        shutil.copy2(p, bak)
    out = []
    with open(p) as f:
        for line in f:
            if '"session.compaction_complete"' in line:
                e = json.loads(line)
                ctu = e.get("data", {}).get("compactionTokensUsed") or {}
                canon = {
                    "inputTokens":      ctu.get("inputTokens",      ctu.get("input", 0))      or 0,
                    "outputTokens":     ctu.get("outputTokens",     ctu.get("output", 0))     or 0,
                    "cacheReadTokens":  ctu.get("cacheReadTokens",  ctu.get("cachedInput", 0)) or 0,
                    "cacheWriteTokens": ctu.get("cacheWriteTokens", 0) or 0,
                }
                for k in ("copilotUsage", "duration", "model"):
                    if k in ctu:
                        canon[k] = ctu[k]
                e["data"]["compactionTokensUsed"] = canon
                line = json.dumps(e, ensure_ascii=False) + "\n"
            out.append(line)
    with open(p, "w") as f:
        f.writelines(out)
PY

Notes

  • Affected sessions in my case both had a session.shutdown event at the end of events.jsonl — i.e., clean shutdowns, no corruption. Purely a schema-drift issue.
  • I suspect any user who ran an older CLI, hit a long-enough conversation to trigger auto-compaction, and then upgraded to 1.0.35-x will have the same problem. Would be worth a one-shot migration on first launch of the new version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:sessionsSession management, resume, history, session picker, and session state

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions