Plannotator Troubleshooting
What You'll Learn
When you encounter issues, you'll be able to:
- Quickly identify the source of problems (port conflicts, Hook event parsing, Git configuration, etc.)
- Diagnose errors through log output
- Apply the correct solution for different error types
- Debug connection issues in remote/Devcontainer modes
The Problem
Plannotator suddenly stopped working, the browser didn't open, or the Hook output error messages. You don't know how to view logs, and you're unsure which step failed. You may have tried restarting, but the problem persists.
When to Use This
You need troubleshooting in the following situations:
- Browser doesn't open automatically
- Hook outputs error messages
- Port conflicts prevent startup
- Plan or code review pages display abnormally
- Obsidian/Bear integration fails
- Git diff shows empty
Core Concepts
Plannotator issues typically fall into three categories:
- Environment Issues: Port conflicts, environment variable configuration errors, browser path issues
- Data Issues: Hook event parsing failures, empty plan content, abnormal Git repository status
- Integration Issues: Obsidian/Bear save failures, remote mode connection problems
The core of debugging is viewing log output. Plannotator uses console.error to output errors to stderr and console.log to output normal information to stdout. Distinguishing between these two helps you quickly identify the problem type.
🎒 Prerequisites
- ✅ Plannotator installed (Claude Code or OpenCode plugin)
- ✅ Basic command line knowledge
- ✅ Familiar with your project directory and Git repository status
Follow Along
Step 1: Check Log Output
Why
All Plannotator errors are output to stderr. Viewing logs is the first step in diagnosing problems.
How to Do It
In Claude Code
When the Hook triggers Plannotator, error messages display in Claude Code's terminal output:
# You might see error examples like this
Error: Port 54321 in use after 5 retries (set PLANNOTATOR_PORT to use different port)In OpenCode
OpenCode captures CLI stderr and displays it in the interface:
[stderr] Failed to parse hook event from stdin
[stderr] No plan content in hook eventWhat You Should See:
- If there are no errors, stderr should be empty or contain only expected prompt messages
- If there are errors, they include the error type (such as EADDRINUSE), error message, and stack trace (if applicable)
Step 2: Handle Port Conflicts
Why
Plannotator starts the server on a random port by default. If a fixed port is occupied, the server tries 5 times (with a 500ms delay each time), then reports an error.
Error Message:
Error: Port 54321 in use after 5 retries (set PLANNOTATOR_PORT to use different port)Solutions
Option A: Let Plannotator Automatically Choose Port (Recommended)
Don't set the PLANNOTATOR_PORT environment variable—Plannotator will automatically choose an available port.
Option B: Use a Fixed Port and Resolve the Conflict
If you must use a fixed port (such as in remote mode), resolve the port conflict:
# macOS/Linux
lsof -ti:54321 | xargs kill -9
# Windows PowerShell
Get-NetTCPConnection -LocalPort 54321 | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }Then reset the port:
# macOS/Linux/WSL
export PLANNOTATOR_PORT=54322
# Windows PowerShell
$env:PLANNOTATOR_PORT = "54322"Checkpoint ✅:
- Trigger Plannotator again, the browser should open normally
- If you still get an error, try a different port number
Step 3: Debug Hook Event Parsing Failures
Why
Hook event is JSON data read from stdin. If parsing fails, Plannotator cannot continue.
Error Message:
Failed to parse hook event from stdin
No plan content in hook eventPossible Causes:
- Hook event is not valid JSON
- Hook event is missing the
tool_input.planfield - Hook version incompatible
Debugging Method
View Hook Event Content
Before the Hook server starts, print the stdin content:
# Temporarily modify hook/server/index.ts
# Add after line 91:
console.error("[DEBUG] Hook event:", eventJson);What You Should See:
{
"tool_input": {
"plan": "# Implementation Plan\n\n## Task 1\n..."
},
"permission_mode": "default"
}Solutions:
- If
tool_input.planis empty or missing, check if the AI Agent correctly generated the plan - If JSON format is wrong, check if Hook configuration is correct
- If Hook version is incompatible, update Plannotator to the latest version
Step 4: Resolve Browser Not Opening
Why
Plannotator uses the openBrowser function to automatically open the browser. If this fails, it could be a cross-platform compatibility issue or an incorrect browser path.
Possible Causes:
- System default browser not set
- Custom browser path invalid
- Special handling issues in WSL environment
- In remote mode, the browser does not open automatically (this is normal)
Debugging Method
Check If in Remote Mode
# View environment variable
echo $PLANNOTATOR_REMOTE
# Windows PowerShell
echo $env:PLANNOTATOR_REMOTEIf the output is 1 or true, it's in remote mode—the browser won't open automatically, which is expected behavior.
Manually Test Browser Opening
# macOS
open "http://localhost:54321"
# Linux
xdg-open "http://localhost:54321"
# Windows
start http://localhost:54321What You Should See:
- If manual opening succeeds, Plannotator server is running normally; the issue is in the auto-open logic
- If manual opening fails, check if the URL is correct (the port might be different)
Solutions:
Option A: Set Custom Browser (macOS)
export PLANNOTATOR_BROWSER="Google Chrome"
# Or use the full path
export PLANNOTATOR_BROWSER="/Applications/Google Chrome.app"Option B: Set Custom Browser (Linux)
export PLANNOTATOR_BROWSER="/usr/bin/firefox"Option C: Remote Mode Manual Open (Devcontainer/SSH)
# Plannotator will output URL and port information
# Copy the URL and open it in your local browser
# Or use port forwarding:
ssh -L 19432:localhost:19432 user@remoteStep 5: Check Git Repository Status (Code Review)
Why
The code review feature relies on Git commands. If the Git repository status is abnormal (such as no commits, Detached HEAD), it causes the diff to show empty or error.
Error Message:
Git diff error for uncommitted: Error: Command failed: git diff HEADDebugging Method
Check Git Repository
# Check if in a Git repository
git status
# Check current branch
git branch
# Check if there are commits
git log --oneline -1What You Should See:
- If output is
fatal: not a git repository, the current directory is not a Git repository - If output is
HEAD detached at <commit>, you're in Detached HEAD state - If output is
fatal: your current branch 'main' has no commits yet, there are no commits yet
Solutions:
Problem A: Not in a Git Repository
# Initialize Git repository
git init
git add .
git commit -m "Initial commit"Problem B: Detached HEAD State
# Switch to a branch
git checkout main
# Or create a new branch
git checkout -b feature-branchProblem C: No Commits
# At least one commit is needed to view diff
git add .
git commit -m "Initial commit"Problem D: Empty Diff (No Changes)
# Create some changes
echo "test" >> test.txt
git add test.txt
# Run /plannotator-review againCheckpoint ✅:
- Run
/plannotator-reviewagain, diff should display normally - If still empty, check for unstaged or uncommitted changes
Step 6: Debug Obsidian/Bear Integration Failures
Why
Obsidian/Bear integration failures don't prevent plan approval, but cause save failures. Errors are output to stderr.
Error Message:
[Obsidian] Save failed: Vault not found
[Bear] Save failed: Failed to open BearDebugging Method
Check Obsidian Configuration
macOS:
cat ~/Library/Application\ Support/obsidian/obsidian.jsonWindows:
cat $env:APPDATA\obsidian\obsidian.jsonWhat You Should See:
{
"vaults": {
"/path/to/vault": {
"path": "/path/to/vault",
"ts": 1234567890
}
}
}Check Bear Availability (macOS)
# Test Bear URL scheme
open "bear://x-callback-url/create?title=Test&text=Hello"What You Should See:
- Bear app opens and creates a new note
- If there's no response, Bear isn't installed correctly
Solutions:
Obsidian Save Failure
- Ensure Obsidian is running
- Check if vault path is correct
- Try creating a note manually in Obsidian to verify permissions
Bear Save Failure
- Ensure Bear is installed correctly
- Test if
bear://x-callback-urlis available - Check if x-callback-url is enabled in Bear settings
Step 7: View Detailed Error Logs (Debug Mode)
Why
Sometimes error messages aren't detailed enough—you need to view complete stack traces and context.
How to Do It
Enable Bun Debug Mode
export DEBUG="*"
plannotator review
# Windows PowerShell
$env:DEBUG = "*"
plannotator reviewView Plannotator Server Logs
Internal server errors are output through console.error. Key log locations:
packages/server/index.ts:260- Integration error logspackages/server/git.ts:141- Git diff error logsapps/hook/server/index.ts:100-106- Hook event parsing errors
What You Should See:
# Successfully saved to Obsidian
[Obsidian] Saved plan to: /path/to/vault/Plan - 2026-01-24.md
# Save failed
[Obsidian] Save failed: Cannot write to directory
[Bear] Save failed: Failed to open Bear
# Git diff error
Git diff error for uncommitted: Error: Command failed: git diff HEADCheckpoint ✅:
- Error logs contain enough information to locate the problem
- Apply the corresponding solution based on error type
Common Pitfalls
❌ Ignoring stderr Output
Wrong Approach:
# Only focus on stdout, ignore stderr
plannotator review 2>/dev/nullRight Approach:
# View both stdout and stderr
plannotator review
# Or separate logs
plannotator review 2>error.log❌ Blindly Restarting the Server
Wrong Approach:
- Restart the server whenever you encounter a problem, without checking the error cause
Right Approach:
- First check error logs to determine the problem type
- Apply the corresponding solution based on error type
- Restart is the last resort
❌ Expecting Browser Auto-Open in Remote Mode
Wrong Approach:
export PLANNOTATOR_REMOTE=1
plannotator review
# Expect browser to open automatically (won't happen)Right Approach:
export PLANNOTATOR_REMOTE=1
plannotator review
# Record the output URL, manually open in browser
# Or use port forwardingSummary
- Plannotator uses
console.errorto output errors to stderr,console.logto output normal information to stdout - Common issues include: port conflicts, Hook event parsing failures, browser not opening, abnormal Git repository status, integration failures
- Core debugging: view logs → locate problem type → apply corresponding solution
- In remote mode, the browser doesn't open automatically; you need to manually open the URL or configure port forwarding
Next Up
In the next lesson, we'll learn Common Problems.
You'll learn:
- How to resolve installation and configuration issues
- Common usage pitfalls and considerations
- Performance optimization recommendations
Appendix: Source Code Reference
Click to expand source code locations
Updated: 2026-01-24
| Feature | File Path | Line Number |
|---|---|---|
| Port retry mechanism | packages/server/index.ts | 79-80 |
| EADDRINUSE error handling | packages/server/index.ts | 320-334 |
| Hook event parsing | apps/hook/server/index.ts | 91-107 |
| Browser opening | packages/server/browser.ts | 45-74 |
| Git diff error handling | packages/server/git.ts | 139-144 |
| Obsidian save logs | packages/server/index.ts | 242-246 |
| Bear save logs | packages/server/index.ts | 252-256 |
Key Constants:
MAX_RETRIES = 5: Maximum port retry countRETRY_DELAY_MS = 500: Port retry delay (milliseconds)
Key Functions:
startPlannotatorServer(): Start plan review serverstartReviewServer(): Start code review serveropenBrowser(): Cross-platform browser openingrunGitDiff(): Execute Git diff commandsaveToObsidian(): Save plan to ObsidiansaveToBear(): Save plan to Bear