Browser tool auto-attaches a screenshot to nearly every Code Mode result, permanently inflating history and app-server memory

Open 💬 1 comment Opened Aug 23, 2026 by TatsuKo-Tsukimi
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using?

26.818.31338 (build 6892); codex-cli 0.149.0-alpha.4

What subscription do you have?

rate_limits payloads report plan_type: prolite

What platform is your computer?

macOS 26.4, Apple Silicon (arm64), 48 GB RAM

What issue are you seeing?

When the active model runs in code_mode_only mode (e.g. gpt-5.6-sol), every tool call is routed through the node_repl js tool. If the script touches the in-app browser at all, the tool result comes back with a full data:image/png;base64,... screenshot attached — even when the script never asked for one.

Measured over a single ~6.5 hour session:

| | |
|---|---:|
| node_repl :: js calls | 864 |
| calls whose result contained an image | 347 |
| of those, scripts referencing any screenshot/image API | 3 |
| images attached without being requested | 344 (99.1%) |

Example of a script that came back with an image attached — it only reads text:

const tab = await browser.tabs.new();
await tab.goto("http://127.0.0.1:<port>/");
await tab.playwright.waitForTimeout(1500);
nodeRepl.write(await tab.playwright.locator("body").innerText({ timeoutMs: 5000 }));

Downstream effects, all measured:

  1. Rollout size. That session's rollout reached 306 MB in 6.5 hours; 91% of its bytes were base64 image data (650 images).
  2. Compaction write amplification. Compaction itself works correctly — the retained-history snapshot rises and falls as expected. But each snapshot re-serializes the retained images. 64 snapshots wrote 188 MB to disk while live retained history peaked at 6.3 MB, i.e. roughly 30x write amplification.
  3. app-server memory. The app-server process reached 22.3 GB physical footprint after 3d20h uptime with 21 rollouts open, of which 21.2 GB was compressed/swapped, growing at roughly 5.5 GB/day. On a 48 GB machine this consumed essentially the entire compressor and filled swap.
  4. Disk. The local sessions directory grew from 140 GB to 182 GB in 4 days (378 new rollout files).

Two notes for whoever triages this:

  • RSS hides the memory growth. Resident was only ~1.0 GB because the rest was compressed; vmmap --summary <pid> | grep "Physical footprint" is the metric that shows it.
  • The heap was dominated by MALLOC_SMALL live allocations (20.3 GB across 5188 regions) rather than MALLOC_LARGE (1.8 GB), so the memory is mostly parsed history structures, not the image blobs themselves.

What steps can reproduce the bug?

  1. Use a model whose metadata is tool_mode: code_mode_only (e.g. gpt-5.6-sol), with the bundled browser plugin enabled.
  2. In Code Mode, run a script that only reads text from a page and never calls any screenshot or image API — for example the snippet above, against any local or public URL.
  3. Inspect the resulting mcp_tool_call_end entry in the session rollout .jsonl.
  4. Its output array contains a data:image/png;base64,... item the script never requested.
  5. Keep working in that session and watch rollout size and app-server footprint grow.

Session ID deliberately omitted — the conversations involved contain confidential work. Happy to supply one privately if it helps.

What is the expected behavior?

Any one of these would address it:

  • Attach a screenshot only when the script actually requests one.
  • Provide a switch to disable auto-attachment. I could not find one: I checked the bundled browser plugin's browser-service.mjs and every NODE_REPL_* / BROWSER_USE_* string in the node_repl binary, and there is no disableScreenshot-style option.
  • Elide or downscale image payloads when writing compaction snapshots, so a retained image is not re-serialized on every subsequent compaction.
  • Apply a low imageDetail default to auto-attached images.

Additional information

These mitigations have independent value: the first fixes the source, while the compaction change fixes the ~30x amplification on its own and would still help if auto-attachment turns out to be intentional.

There is also no retention policy for the sessions directory, so all of the above accumulates permanently.

View original on GitHub ↗

1 Comment

github-actions[bot] contributor · 5 days ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #40111

Powered by Codex Action