Skip to content

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

Description

@chrisspen

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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.

Activity

  1. github-actions commented on Feb 16, 2026

    @github-actions

    Found 3 possible duplicate issues:

    1. Corrupted image in context permanently breaks session — workaround and suggested fix #24387
    2. Corrupted image in context causes persistent API 400 errors, breaking the entire chat session #19031
    3. [BUG] Conversation breaks(throws 400) after image encoding error #17452

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. github-actions commented on Feb 20, 2026

    @github-actions

    This issue has been automatically closed as a duplicate of #24387.

    If this is incorrect, please re-open this issue or create a new one.

    🤖 Generated with Claude Code

  3. github-actions commented on Feb 28, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  4. locked as resolved and limited conversation to collaborators on Feb 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions