[BUG] Claude becomes permanently unresponsive when processing invalid/malformed image data from screenshot tool

Resolved 💬 3 comments Opened Feb 16, 2026 by chrisspen Closed Feb 20, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When using Browserless (headless Chrome in Docker) to take screenshots, if the screenshot request fails or returns non-image data (e.g., an error page, HTML, or garbage data), Claude
attempts to process it as an image anyway. This causes the session to hang indefinitely - Claude becomes completely unresponsive and never recovers.

What Should Happen?

  • Claude Code or the Claude API should validate that image data (e.g. file <image_path>) is actually a valid image before processing
  • If invalid, return an error message like "Screenshot failed: invalid image data received"
  • The session should remain functional

Error Messages/Logs

Error: Error during compaction: Error: API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"Could not process image"},"request_id":"req_023CYAxmif1c3suh5PK6yA75"}

Steps to Reproduce

  1. Run Browserless in a VM with Docker via: docker run --rm -p "${PORT}:3000" -e "CONCURRENT=10" -e "TOKEN=${TOKEN}" ghcr.io/browserless/chromium
  2. Launch Claude code in the same VM with claude --dangerously-skip-permissions and explain that there's a Browserless service running on it's VM at PORT with TOKEN and tell it to read http://localhost:${PORT}/docs to understand how to access it.
  3. Ask Claude to take a screenshot of some non-existent webpage on a non-existant port. (e.g. https://localhost:9898)
  4. Browserless returns a textural error response instead of a screenshot image.
  5. Claude receives this data and attempts to process it as an image.
  6. Claude effectively dies, responding to all further input with: `{"type":"error","error":{"type":"invalid_request_error","message":"Could not process

image"},"request_id":"req_011DYAxmif1h3soh5BK6yf91"} since this malformed image is now baked into the session and cannot be removed, except by using /clear` or exiting and restarting Claude Code in a new session.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.0.61

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Xterm

Additional Information

I had Claude write a BROWSERLESS.md file explaining this problem as well as how to avoid making it, which seems to partially solve it, although Claude will still occasionally forget these rules and kill itself by trying to process a non-image as an image. The file it generated to help itself is:

Browserless Usage Guide (For AI Agents)

This project uses a Browserless container to let agents interact with a real Chromium browser via HTTP.

CRITICAL: Docker Networking (READ THIS FIRST)

Browserless runs inside a Docker container. This means:

  • localhost inside the container is the container itself, NOT the host machine
  • Trying to screenshot http://localhost:5173/ will return ERR_CONNECTION_REFUSED (plain text, not an image)
  • If you try to view this text error as an image, the Claude API will crash with "Could not process image"

Correct URLs for Screenshots

| Wrong (crashes) | Correct |
|------------------------------|----------------------------------|
| http://localhost:5173/ | http://172.17.0.1:5173/ |
| http://127.0.0.1:5173/ | http://172.17.0.1:5173/ |

The IP 172.17.0.1 is Docker's bridge gateway - it routes to the host machine.

ALWAYS Validate Before Viewing

# Take screenshot
curl -sS -X POST "http://localhost:3003/chromium/screenshot?token=TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "http://172.17.0.1:5173/", "options": {"type": "png"}}' \
  -o /tmp/screenshot.png

# VALIDATE - browserless returns text errors, not images, on failure
if file /tmp/screenshot.png | grep -q "PNG image"; then
  echo "Screenshot OK"
else
  echo "ERROR: Screenshot failed. Response was:"
  cat /tmp/screenshot.png
  exit 1
fi

Non-Negotiable Rules

  • Use Browserless REST API calls only.
  • Do not write local Playwright/Selenium scripts for browser interaction.
  • Never assume Browserless is on a fixed port. Always use the exact host:port provided by the user/environment.
  • ALWAYS use 172.17.0.1 instead of localhost when targeting host services from browserless.
  • ALWAYS validate screenshot output is actually a PNG before trying to view it.
  • If you are inside a VM:
  • Browserless endpoint is local to the VM: http://localhost:<port>
  • Dev server must be accessed via Docker bridge: http://172.17.0.1:<port>

Connection

  • Base URL: http://localhost:<port>
  • Token auth: query param ?token=<TOKEN>
  • Docs: http://localhost:<port>/docs

Example tokenized endpoint:

  • http://localhost:<port>/chromium/screenshot?token=<TOKEN>

1) Take a Screenshot

curl -sS -X POST "http://localhost:<port>/chromium/screenshot?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "http://<host-ip>:8777/admin/",
    "gotoOptions": { "waitUntil": "networkidle2", "timeout": 60000 },
    "options": { "fullPage": true, "type": "png" }
  }' > /tmp/page.png

Notes:

  • Navigation waits belong in gotoOptions.
  • Screenshot settings belong in options.

2) Capture Console Errors / JS State

Use Browserless function endpoints (if enabled) to run scripted browser steps on the server side.
Pattern:

curl -sS -X POST "http://localhost:<port>/chromium/function?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "module.exports = async ({ page, context }) => { await page.goto(\"http://<host-ip>:8777/admin/\", { waitUntil: \"networkidle2\" }); const logs = []; page.on(\"console\", m => logs.push(m.text())); page.on(\"pageerror\", e => logs.push(String(e))); await page.waitForTimeout(1500); return { url: page.url(), logs }; }"
  }'

If your Browserless build does not expose /chromium/function, use the documented equivalent in /docs.

3) Admin Login Pattern

If you need authenticated screenshots:

  1. Open login page.
  2. Fill username/password.
  3. Submit.
  4. Navigate target admin URL.
  5. Screenshot.

If doing this via REST function endpoint, keep it in one browser session so cookies persist.

4) Troubleshooting

  • Blank screenshot:
  • increase gotoOptions.timeout
  • wait for networkidle2
  • add explicit wait before capture
  • 401/403 from Browserless:
  • token missing or invalid
  • page unreachable:
  • wrong host IP/port
  • devserver not running or not bound externally

5) Recommended Agent Workflow

  1. Make code change.
  2. Wait for devserver reload.
  3. Capture screenshot via Browserless.
  4. Compare before/after and inspect console errors.
  5. Repeat until layout/behavior matches expectation.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗