Common issues and solutions.
Error: listen tcp :8080: bind: address already in use
Solution:
-
Check what's using the port:
lsof -i :8080
-
Kill the existing process:
kill -9 <PID>
-
Or use a different port:
./markdowninthemiddle --addr :9090
Error: listen tcp :80: bind: permission denied
Solution:
-
Use a port > 1024 (don't need sudo):
./markdowninthemiddle --addr :8080
-
Or run with sudo (not recommended):
sudo ./markdowninthemiddle --addr :80
Error:
chromedp: failed to connect to Chrome at http://chrome:9222
Solution:
-
Check Chrome service is running:
docker compose ps chrome
Should show
Upandhealthy -
Restart Chrome:
docker compose restart chrome
-
Check Chrome logs:
docker compose logs -f chrome
-
Verify Chrome port is open:
curl http://localhost:9222/json/version
Error:
chromedp: failed to connect to Chrome at http://localhost:9222
Solution:
-
Start Chrome with debugging protocol:
# macOS /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ --remote-debugging-port=9222 & # Linux google-chrome --remote-debugging-port=9222 & # Windows "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
-
Or specify the Chrome URL:
./markdowninthemiddle --chrome-url http://localhost:9222
-
Or use helper script:
./scripts/start-chrome.sh & ./markdowninthemiddle
Error:
error generating certificate: open ./certs: permission denied
Solution:
-
Create certs directory:
mkdir -p certs chmod 755 certs
-
Generate certificate manually:
./markdowninthemiddle gencert --dir ./certs
-
Or let Docker handle it:
cd docker docker compose up -d
Error:
http: TLS handshake error from [::1]:12345: tls: first record does not look like a TLS handshake
Solution:
This usually means sending HTTP to an HTTPS port.
-
Use HTTPS with the proxy:
curl -k -x https://localhost:8080 http://example.com
-
Or disable TLS:
./markdowninthemiddle --tls=false
Error: Browser shows "certificate not trusted" warning
Solution:
For MITM mode, you need to trust the CA certificate:
- See HTTPS_SETUP.md for TLS setup
- See MITM_SETUP.md for certificate installation
Check:
-
Verify conversion is enabled:
./markdowninthemiddle --convert=true
-
Check response Content-Type:
curl -x http://localhost:8080 http://example.com -sD - | grep "Content-Type"
Should be
text/htmlortext/markdown -
Check response headers:
curl -x http://localhost:8080 http://example.com -sD - | grep "X-"
Look for
X-Token-Count(shows it was converted)
Check:
-
Enable JSON conversion:
./markdowninthemiddle --convert-json --template-dir ./my-templates
-
Verify Content-Type is
application/json:curl -x http://localhost:8080 https://api.example.com/data -sD - | grep "Content-Type"
-
Check if template matches:
- Enable debug logging:
./markdowninthemiddle --convert-json --template-dir ./my-templates --log-level debug
- Look for "template matched" in logs
- Enable debug logging:
-
Verify template naming:
- Template:
api.example.com__users.mustache - URL:
https://api.example.com/users - Scheme is stripped before matching
- Template:
Check:
-
Enable negotiate-only mode:
./markdowninthemiddle --negotiate-only
-
Send Accept header:
curl -x http://localhost:8080 \ -H "Accept: text/markdown" \ http://example.comWithout header, HTML is returned as-is.
Check:
-
Enable cache and verify directory:
./markdowninthemiddle --cache-dir ./cache
-
Check cache directory exists and is writable:
ls -la cache/
-
Make the same request twice (should be faster second time):
curl -x http://localhost:8080 http://example.com curl -x http://localhost:8080 http://example.com # Should be cached -
Check cache files were created:
ls -la cache/
Check:
-
Verify respect-headers is enabled (default):
# In config.yml cache: respect_headers: true
-
Check the API response Cache-Control header:
curl http://example.com/api -sD - | grep "Cache-Control"
-
Some APIs use
no-storeorno-cache(won't be cached)
Check:
-
Verify encoding is correct:
./markdowninthemiddle --config ./config.yml # Check: conversion.tiktoken_encoding in config -
Check response has X-Token-Count header:
curl -x http://localhost:8080 http://example.com -sD - | grep "X-Token-Count"
-
Invalid encoding will fall back to estimating:
# Valid: cl100k_base, p50k_base # Invalid: gibberish → token count will be estimated
Check:
-
Verify filter pattern:
./markdowninthemiddle \ --allow "^https://api\.example\.com/" \ --allow "^https://docs\.example\.com/"
-
Test with a non-matching URL:
curl -x http://localhost:8080 http://other.com
Should return 403 Forbidden
-
Test with matching URL:
curl -x http://localhost:8080 https://api.example.com/data
Should work (200 OK)
-
Check regex pattern is valid:
- Use regex101.com to test
- Use Go regex dialect
^= start,$= end,\.= literal dot
Check:
-
Verify docker-compose.yml is valid:
cd docker docker compose config -
Check logs:
docker compose logs -f
-
Look for common errors:
- Port conflicts:
docker ps | grep 8080 - Image build failures:
docker compose build --progress=plain - Volume mount issues:
docker compose psand check volumes
- Port conflicts:
Check:
-
View detailed logs:
docker compose logs proxy
-
Common causes:
- Config file missing (check volume mounts)
- Port already in use
- Cert generation failed
-
Rebuild and restart:
docker compose down -v docker compose build docker compose up -d
Check:
-
View Chrome logs:
docker compose logs chrome
-
Test Chrome health manually:
docker compose exec chrome curl http://localhost:9222/json/version -
Increase health check timeout (if needed): Edit
docker/docker-compose.yml:healthcheck: timeout: 15s # Increase from 10s
Check:
-
Enable caching:
./markdowninthemiddle --cache-dir ./cache
-
Reduce Chrome pool size if low memory:
./markdowninthemiddle --chrome-pool-size 2
-
Check system resources:
top -o %MEM # Memory usage -
Use HTTP transport instead of chromedp:
./markdowninthemiddle --transport http
Check:
-
Reduce Chrome pool size:
--chrome-pool-size 2 # Default is 5 -
Limit response body size:
--max-body-size 5242880 # 5 MB instead of 10 MB -
Disable caching if large:
# Don't use --cache-dir or --output-dir
Problem: docker compose command not found
Solution:
- Install Docker Desktop from docker.com
- Or use
docker-compose(with dash) on older versions:docker-compose up -d # Old syntax docker compose up -d # New syntax
Problem: Volume mounts show permission denied
Solution:
- On macOS, Docker Desktop handles permissions automatically
- On Windows with WSL2:
cd /mnt/c/Users/YourUser/Projects/markdowninthemiddle docker compose up -d
-
Check logs:
./markdowninthemiddle 2>&1 | tee proxy.log
-
Enable debug logging:
./markdowninthemiddle --log-level debug
-
Check configuration:
./markdowninthemiddle --help cat config.yml | grep -A5 conversion -
Report on GitHub:
- GitHub Issues
- Include logs, configuration, error messages
- Describe what you expected vs what happened
- CONFIGURATION.md - Configuration options
- HTTPS_SETUP.md - TLS/HTTPS setup
- MITM_SETUP.md - MITM certificate setup
- CHROMEDP.md - JavaScript rendering issues