Skip to content
PEN Docs

Troubleshooting

Quick fixes for the most common PEN issues.

Connection Issues

Browser not running or wrong port

Symptom: CDP connect failed: connection refused

Fix: The browser wasn't launched with --remote-debugging-port=9222. Kill all browser processes and relaunch:

bash
# macOS
open -a "Google Chrome" --args --remote-debugging-port=9222

# Windows
& "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222

# Linux
google-chrome --remote-debugging-port=9222

Verify: http://localhost:9222/json should return a JSON array. If it doesn't, the browser wasn't fully killed before relaunch.

Windows tip: Open Task Manager (Ctrl+Shift+Esc) and end all Chrome/Edge processes before relaunching.

macOS tip: Run killall "Google Chrome" before relaunching.

No targets found

Symptom: no targets found

Fix: Open a tab. PEN needs at least one page target to work with.

Invalid CDP URL

Symptom: invalid CDP URL

Fix: PEN only talks to localhost (localhost, 127.0.0.1, ::1). For remote browsers, tunnel with SSH:

bash
ssh -L 9222:localhost:9222 user@remote-server
pen --cdp-url http://localhost:9222

Connection drops mid-operation

Symptom: Browser disconnected during operation

Cause: Browser crashed or tab closed during a heap snapshot or trace.

What PEN does: Detects the disconnection automatically (monitors the browser context for cancellation), marks the connection as lost, cleans up partial temp files via defer, releases domain locks, and returns isError explaining what happened. On the next call, PEN tries to reconnect (up to 3 retries, exponential backoff from 1s to 10s).

IDE Issues

pen: command not found

Fix: The binary isn't on your PATH. Either add it, or use the full path in your IDE config:

json
"command": "/full/path/to/pen"

IDE doesn't see PEN tools

Fix: Restart your editor. Most IDEs don't hot-reload MCP configs.

PEN doesn't respond

Fix: Check the MCP output panel. PEN logs to stderr — look for connection errors or startup failures there.

Tool-Specific Issues

Rate limit errors

Symptom: pen_heap_snapshot has a 10s cooldown. Try again in 6s

Fix: Wait it out. Rate limits prevent resource exhaustion:

ToolCooldown
pen_heap_snapshot10s
pen_capture_trace5s
pen_collect_garbage5s

Domain lock conflicts

Symptom: HeapProfiler is already in use by HeapProfiler (held for 12s)

Cause: Two tools tried to use the same exclusive CDP domain at once (e.g., pen_cpu_profile while pen_capture_trace is still running).

Fix: Let the first operation finish. The error message tells you which tool holds the lock and how long it’s been running. PEN also suggests alternative tools you can use in the meantime (e.g., pen_performance_metrics instead of pen_cpu_profile). Use pen_status to see all active operations.

Lighthouse not found

Symptom: lighthouse CLI not found

Fix: Install Lighthouse globally:

bash
npm install -g lighthouse

Every other PEN tool works without Lighthouse. Only pen_lighthouse needs it.

Lighthouse timeout

Symptom: Lighthouse audit hangs or times out on complex pages.

Fix: Lighthouse has its own internal timeout. If the page is extremely large or slow, the audit may fail. Try:

  • Auditing a simpler page first
  • Reducing the number of categories
  • Checking that the browser isn't frozen or unresponsive

Large heap snapshot warnings

Symptom: Large heap detected. Analysis limited to top retainers.

Cause: The heap is huge (>500 MB). Big enterprise SPAs can do this.

What PEN does: Keeps streaming to disk (constant memory — the snapshot never sits in RAM). Limits analysis depth to stay fast. The raw data is still complete. If the snapshot exceeds 2 GB, PEN aborts with an error suggesting pen_heap_sampling as a lower-overhead alternative.

Trace buffer overflow

Symptom: Trace truncated at Xs due to buffer limit

Cause: Chrome's trace buffer filled during capture.

Fix: Reduce trace duration or use fewer trace categories:

text
pen_capture_trace with duration=3 (shorter)

Console buffer full

Symptom: Console messages appear to be missing.

Cause: The console buffer holds 1,000 messages max. When full, the oldest 100 are evicted.

Fix: Use pen_console_messages with last=N to get recent messages, or use clear=true to reset the buffer periodically.

Trace file too large

Symptom: Trace file is X MB — exceeds the 100 MB limit

Fix: pen_trace_insights caps at 100 MB to avoid blowing up during JSON parsing. The trace capture itself (pen_capture_trace) has a 500 MB hard cap — if the trace data exceeds this during streaming, capture is aborted. Record shorter traces or use fewer categories.

Page and Navigation Issues

Page navigates during profiling

Cause: SPA route change or full page reload during an active profile.

What PEN does:

  • Same-page navigation (SPA): continues, notes it in output
  • Full reload: aborts current operation, returns partial results

Blocked URL scheme

Symptom: URL scheme is not allowed. Only HTTP and HTTPS URLs are accepted.

Cause: Attempted to navigate to a javascript:, data:, file:, or other non-HTTP URL.

Fix: This is a security feature. Only HTTP and HTTPS URLs are allowed for navigation and Lighthouse.

No forward history

Symptom: Error when using pen_navigate with action: forward

Cause: The browser has no forward navigation history from the current entry.

Fix: You can only go forward if you've previously gone back.

Security Issues

Expression blocked

Symptom: Expression blocked by the security filter when using pen_evaluate.

Cause: The expression hit one of PEN's blocklist patterns (fetch, document.cookie, eval, localStorage, etc.).

Fix: That's intentional. See Security for the full list.

Path access denied

Symptom: path resolves outside project root — access denied

Cause: A source tool tried to access a file outside --project-root.

Fix: Set --project-root to the correct directory, or access files within the allowed path.

HTTP Transport Issues

Session not found / tools not working

Symptom: Tools return errors or each request starts a new session.

Fix: You must send an initialize request first, then include the Mcp-Session-Id header from the response in all subsequent requests. Without it, each POST creates a new session.

bash
# 1. Initialize — save the session ID from the response header
curl -s http://localhost:6100/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -D - \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","clientInfo":{"name":"test"},"capabilities":{}}}'

# 2. Use the Mcp-Session-Id from step 1 in all subsequent requests
curl -s http://localhost:6100/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: YOUR_SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"pen_status","arguments":{}}}'

SSE response format

Symptom: Response looks like event: message / data: ... instead of plain JSON.

Cause: MCP Streamable HTTP uses Server-Sent Events. Each response is prefixed with event: message\ndata:. This is the correct format — your client needs to parse SSE.

Tip: Use --stateless flag for simpler testing. In stateless mode, no session ID tracking is needed.

Port already in use

Symptom: bind: address already in use

Fix: A previous PEN instance is still running. Kill it, or use a different port:

bash
# Windows — find and kill the process
netstat -ano | findstr :6100
taskkill /PID <pid> /F

# macOS/Linux
lsof -i :6100
kill <pid>

# Or just use a different port
pen --transport http --addr localhost:6200