Backtrack rewind sets context remaining to 0% and triggers auto-compaction

Open 💬 9 comments Opened Jan 21, 2026 by yiwenlu66
💡 Likely answer: A maintainer (swordfish444, contributor) responded on this thread — see the highlighted reply below.

Summary

After using the TUI backtrack/rewind flow (Esc to open transcript overlay, select a previous user message, Enter to rollback), the context indicator jumps to 0% left and the next turn is auto-compacted, even when the post-rollback thread should be far below the model context window.

Version

  • Repo: openai/codex
  • Commit: 16b9380e99474c87502c22ed99bac497d116e724

Repro

  1. Start a Codex TUI session and exchange a few turns (enough to have non-empty history).
  2. Confirm the bottom-bar context indicator is not near 0% left.
  3. Press Esc twice to open the transcript overlay (backtrack preview).
  4. Use Left to select an earlier user message.
  5. Press Enter to rollback.
  6. Observe the context indicator becomes 0% left and the next user turn triggers an automatic compact.

Expected

  • After rollback, token/context usage reflects the smaller history and the context indicator shows substantial remaining context.
  • Auto-compact should not run unless the post-rollback prompt actually exceeds the auto-compact threshold.

Actual

  • Immediately after rollback, remaining context shows 0% left.
  • A compact runs even when the post-rollback thread should be well below the context window.

Suspected cause

The rollback handler recomputes token usage from a heuristic estimate rather than server-provided token usage:

  • codex-rs/core/src/codex.rs:2522 handlers::thread_rollback(...) calls sess.recompute_token_usage(...).
  • codex-rs/core/src/codex.rs:1626 Session::recompute_token_usage(...) uses ContextManager::estimate_token_count(...).
  • codex-rs/core/src/context_manager/history.rs:87 estimate_token_count(...) estimates by JSON-serializing history items (serde_json::to_string(item)) and then calling byte/token heuristics.

This can drastically overestimate the prompt size (JSON framing overhead, large structured fields, image/base64 fields, etc.), which then drives:

  • The TUI context indicator (codex-rs/tui/src/chatwidget.rs:906 uses info.last_token_usage.percent_of_context_window_remaining(window))
  • The auto-compact guard (token usage estimate feeds get_total_token_usage / auto_compact_token_limit).

Possible fixes

  • After rollback, clear token usage info (emit TokenCount { info: None }) until the next real model response provides accurate counts.
  • Or, compute the estimate from the normalized prompt representation (same normalization used for for_prompt()), and avoid counting JSON framing. If images are present, estimate image token cost instead of base64 length.

View original on GitHub ↗

9 Comments

0xdeafbeef · 6 months ago

Same thing if you change model and compact.

<img width="954" height="444" alt="Image" src="https://github.com/user-attachments/assets/d57d3e3d-7a35-48ef-a348-c5002889e89b" />

sahir2k · 5 months ago

facing this as well

swordfish444 contributor · 5 months ago

@etraut-openai This looks like the same symptom family as #9417 / #9257 (“context remaining goes to 0% after a history mutation”), just triggered by backtrack/rollback instead of compaction.

The suspected cause in the report seems plausible: recompute_token_usage estimating from serde_json::to_string(item) will overcount (JSON framing + large structured fields), which can push the indicator to 0% and trip auto-compact.

A low-risk stopgap could be: after rollback, clear token usage info (treat as unknown) until the next real server-provided token count arrives. That avoids bogus “0% remaining” and unnecessary auto-compaction.

Longer term, it seems safer to estimate from the normalized prompt representation (what’s actually sent) rather than serialized history structs.

Alek2077 · 5 months ago

Facing the same issue. It permanently burns my sessions, some of which are very important.
So now it's clear the huge disadvantages Codex CLI has over some of the other tools:

  1. No undo/rewind feature on code changes
  2. No proper 'safe' undo on conversation

These are huge usability features.

miraclebakelaser contributor · 5 months ago

This has become a constant issue for me when backtracking. Context frequently gets crushed to 0%.

Pasting an image into a conversation perpetually poisons, even after compactions. Every single backtrack following an image input will lead to 0% context.

Alek2077 · 5 months ago

@miraclebakelaser I managed to change from 0% to 90%+ by messing with model_auto_compact_token_limit in toml.config
and starting the convo with the flag codex resume --last --autocompact=off
and codex resume --last -c model_auto_compact_token_limit=10000000,
but unsure how usable the conversation is anymore. I just started a new convo..

miraclebakelaser contributor · 5 months ago

@Alek2077 codex resume --last --autocompact=off doesnt seem like a valid command.
codex resume --last -c model_auto_compact_token_limit=10000000 doesn't fix the issue for me. The conversation resumes at 0% context.

Alek2077 · 5 months ago

@miraclebakelaser My bad, the first one indeed is invalid command, but something did fix it - either increasing the model_auto_compact_token_limit in config.toml, or running directly on the 'resume' command. Try it, try increasing compaction to 300k, that's above the max limit, it might actually prevent compacting completely. Let it run for one turn, see if compaction happens and if not, after Codex does one turn, it might change the percentage.

but again, these are just workarounds and we do need a proper fix.

runfence · 1 month ago

Same issue. I was around at 80%, asked a few questions, then reverted to 80% point and asked another question which triggered compaction.