Tomcat Troubleshooting Guide
Introduction
Tomcat problems show up as startup failures, 404/500 responses, 502 from Nginx, or silent hangs on shutdown. This chapter maps symptoms to log files, commands, and fixes—a structured companion to Logging and Access Log and the project chapters.
Prerequisites
Step Zero: Quick Health Check
export CATALINA_HOME=/opt/tomcat
./bin/catalina.sh version
curl -I http://127.0.0.1:8080/
ss -tlnp | grep 8080
ls -lt $CATALINA_HOME/logs/ | head -5| Check | Healthy |
|---|---|
| version | Tomcat 10.1.x, JDK 17+ |
| curl | 200 or expected redirect |
| ss | Listener on 8080 (often 127.0.0.1) |
| logs/ | Recent dated files updating |
Log Files First
| Symptom | Read first |
|---|---|
| Won't start | logs/catalina.yyyy-mm-dd.log |
| App 500 | logs/localhost.yyyy-mm-dd.log |
| Deploy failed | catalina.* deploy lines |
| HTTP access pattern | localhost_access_log.*.txt (if enabled) |
| Nginx 502 | /var/log/nginx/error.log + Tomcat catalina |
grep -i "SEVERE\|ERROR\|Exception" $CATALINA_HOME/logs/catalina.$(date +%Y-%m-%d).log | tail -20
grep -i "Exception" $CATALINA_HOME/logs/localhost.$(date +%Y-%m-%d).log | tail -20Startup Failures
Port already in use
java.net.BindException: Address already in usess -tlnp | grep 8080
# stop Spring Boot, other Tomcat, or Docker containerFix: stop conflict or change Connector port in server.xml.
JAVA_HOME not set
Neither the JAVA_HOME nor the JRE_HOME environment variable is definedFix: set JAVA_HOME, restart shell or systemd unit — chapter 04.
server.xml parse error
org.xml.sax.SAXParseExceptionFix: restore conf/server.xml.bak, validate XML tags, restart.
OutOfMemoryError on startup
Fix: lower app footprint or raise -Xmx in setenv.sh — JVM tuning.
HTTP 404
| Cause | Fix |
|---|---|
| Wrong context path | WAR hello.war → /hello/..., not /... alone |
| Deploy incomplete | Wait; check catalina.log for deploy finished |
| Wrong WAR name | finalName vs URL |
| Nginx path strip error | Fix proxy_pass slashes — Nginx path rules |
App only registers /api | curl full path /context/api |
curl -v http://127.0.0.1:8080/blog-api/posts
curl -v -H "Host: app.example.com" http://127.0.0.1/blog-api/postsHTTP 500
Application exception—stack trace in localhost.*.log.
Common causes:
- Missing
WEB-INF/libdependency NullPointerExceptionin Servlet- Spring Boot misconfiguration on WAR deploy
Fix code or config; redeploy WAR; retest.
502 / 504 from Nginx
| Code | Meaning | Tomcat-side check |
|---|---|---|
| 502 | Nginx cannot connect | Tomcat down; wrong bind (127.0.0.1 vs 0.0.0.0) |
| 504 | Upstream timeout | Slow app; raise proxy_read_timeout |
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/blog-api/posts
sudo tail -20 /var/log/nginx/error.log503 / Thread Exhaustion
Symptoms: requests hang then fail; CPU moderate; many active threads.
Check server.xml maxThreads, slow DB/API calls, connection leaks.
Mitigation: fix slow path, tune threads/heap — chapter 13; restart Tomcat to recover.
ClassLoader / ClassNotFoundException
| Pattern | Fix |
|---|---|
jakarta.servlet not found on Tomcat 9 | Upgrade to Tomcat 10 for Boot 3 |
javax.servlet on Tomcat 10 | Migrate app to Jakarta |
Duplicate servlet API in WEB-INF/lib | Remove; use provided |
| JDBC driver missing for JNDI | Put driver in lib/ |
jar tf target/app.war | grep WEB-INF/libJSP / work/ Issues
JSP changes ignored:
$CATALINA_HOME/bin/shutdown.sh
rm -rf $CATALINA_HOME/work/Catalina/localhost/myapp
$CATALINA_HOME/bin/startup.shShutdown Hangs
shutdown.sh waits forever:
- Shutdown port 8005 blocked or wrong
- Non-daemon threads in app prevent exit
ss -tlnp | grep 8005
# last resort after investigation:
kill $(pgrep -f catalina)Fix shutdown port config; fix app thread pools; avoid kill -9 habitually.
Encoding / Garbled Text
- Connector
URIEncoding="UTF-8"— server.xml - Request
setCharacterEncoding("UTF-8")or Filter - DB and JSON UTF-8 end-to-end
systemd / Docker
| Environment | Check |
|---|---|
| systemd | journalctl -u tomcat -n 100 |
| Docker | docker logs tomcat |
| Wrong user | Permission denied on logs/, webapps/ |
Cross-Track Symptom Index
| Symptom | See also |
|---|---|
| Nginx 502 to 8080 | Nginx troubleshooting |
| Spring Boot WAR fails | chapter 14 |
| Maven WAR empty | chapter 08 |
| MySQL connection errors | Spring Boot JDBC |
Emergency Recovery Checklist
shutdown.shorsystemctl stop tomcat- Backup
conf/if mid-edit - Read last 50 lines of
catalina.*andlocalhost.* - Fix one issue; start with
catalina.sh runforeground - Loopback
curlbefore Nginx - Re-enable Nginx only when Tomcat stable
FAQ
Tomcat starts but all apps 404?
Host appBase wrong; empty webapps/; deploy errors in log.
How to thread dump?
jstack <pid> on Linux when hung—advanced; restart often needed on small VPS.
Two Tomcats after reboot?
Duplicate systemd + manual startup.sh—disable one service.
Works on Windows, fails Linux?
Line endings, case sensitivity, JAVA_HOME, paths with spaces.
Enable remote debug?
CATALINA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 — dev only; firewall port.