[BUG] Claude becomes permanently unresponsive when processing invalid/malformed image data from screenshot tool
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
- Run Browserless in a VM with Docker via:
docker run --rm -p "${PORT}:3000" -e "CONCURRENT=10" -e "TOKEN=${TOKEN}" ghcr.io/browserless/chromium - Launch Claude code in the same VM with
claude --dangerously-skip-permissionsand 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. - Ask Claude to take a screenshot of some non-existent webpage on a non-existant port. (e.g. https://localhost:9898)
- Browserless returns a textural error response instead of a screenshot image.
- Claude receives this data and attempts to process it as an image.
- 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:
localhostinside the container is the container itself, NOT the host machine- Trying to screenshot
http://localhost:5173/will returnERR_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.1instead oflocalhostwhen 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:
- Open login page.
- Fill username/password.
- Submit.
- Navigate target admin URL.
- 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
- Make code change.
- Wait for devserver reload.
- Capture screenshot via Browserless.
- Compare before/after and inspect console errors.
- Repeat until layout/behavior matches expectation.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗