What this usually means
Spring Boot's auto-configuration and component scanning hide a lot of complexity. When startup fails, the root cause is almost never the obvious exception. Most failures stem from conditional beans not matching, conflicting bean definitions, misconfigured data sources, or classloader issues. The framework logs INFO-level messages that look normal but mask a cascading failure. You need to look at the auto-configuration report and the full stack trace, not just the last line.
The first ten minutes — establish facts before touching code.
- 1Run `mvn spring-boot:run` or `java -jar app.jar` with `--debug` to get auto-configuration report: `java -jar app.jar --debug`
- 2Check the application logs for `Conditions evaluation report` – grep for 'Positive matches' and 'Negative matches'
- 3Verify no other process is using the default port: `lsof -i :8080` (or `netstat -ano | findstr :8080` on Windows)
- 4If using an embedded database, ensure the file path is writable and no lock exists: `ls -la ./mydb.mv.db`
- 5Enable Spring Boot's startup failure analysis by setting `spring.autoconfigure.exclude` to isolate problematic auto-configuration classes
- 6Use `--trace` instead of `--debug` for full HTTP request logging if startup involves external calls
The specific files, logs, configs, and dashboards that usually own this bug.
- searchApplication logs – always the first place: `tail -100f app.log` or `journalctl -u myapp.service`
- searchAuto-configuration report generated with `--debug`: shows which conditions matched and which didn't
- search`application.properties` or `application.yml` – check for misconfigured datasource URLs, ports, or missing required properties
- search`src/main/resources/` – verify presence of `bootstrap.yml` if using Spring Cloud Config
- searchPOM or build.gradle – check for version conflicts, especially with Spring Boot starters or transitive dependencies
- searchDocker logs if containerized: `docker logs <container-id> 2>&1 | grep ERROR`
Practical causes, not theory. These are the things you will actually find.
- warningPort conflict: another service or a zombie Java process holds the required port
- warningMissing or misconfigured datasource: Spring Boot fails to create a DataSource bean because the URL is wrong or the database is unreachable
- warningCircular dependencies between beans, often caused by `@Autowired` on constructors in a cycle
- warningAuto-configuration class not found because a required starter is missing from the classpath (e.g., missing `spring-boot-starter-web`)
- warningClasspath scanning picks up unwanted beans from test directories or duplicate JARs
- warningInvalid YAML indentation or properties values that cause silent failures
Concrete fix directions. Pick the one that matches your root cause.
- buildResolve port conflict by killing the blocking process: `kill -9 $(lsof -t -i:8080)` or change the port in `application.properties` with `server.port=0` for random port
- buildFix datasource configuration: double-check `spring.datasource.url`, `username`, `password`, and ensure the database is running and accessible
- buildBreak circular dependencies by using `@Lazy` on one of the beans or refactoring to use setter injection
- buildAdd missing starter dependency: `spring-boot-starter-web` for web apps, `spring-boot-starter-data-jpa` for JPA, etc.
- buildExclude problematic auto-configuration classes using `@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})` until the root cause is fixed
- buildClean and rebuild: `mvn clean install -U` to force re-download of dependencies and clear cached classpath issues
A fix you cannot prove is a guess. Close the loop.
- verifiedRestart the application and confirm it reaches `Started Application in X seconds` without exceptions
- verifiedHit the health endpoint: `curl http://localhost:8080/actuator/health` should return `{"status":"UP"}`
- verifiedCheck the auto-configuration report again to ensure all expected positive matches are present and negative matches are expected
- verifiedRun a simple integration test that starts the application context: `@SpringBootTest` should pass
- verifiedMonitor logs for at least 30 seconds after startup to ensure no delayed failure (e.g., connection pool exhaustion)
Things that make this bug worse or harder to find.
- warningDon't blindly add `@EnableAutoConfiguration` or `@ComponentScan` without base packages – it can pull in unintended beans
- warningDon't ignore `WARN` logs – they often precede the actual failure by lines
- warningDon't use `@SpringBootApplication` on a non-main class – it can cause multiple application contexts
- warningDon't set `spring.jpa.hibernate.ddl-auto=update` in production – it may hide schema issues and cause startup delays
- warningDon't kill all Java processes with `killall java` – you might terminate critical services; always check the PID first
- warningDon't rely solely on the last line of the stack trace – the root cause is often several frames up
The Case of the Silent Port Thief
Timeline
- 09:15Deploy new build to staging via Jenkins. Job succeeds.
- 09:18Health check fails. curl returns 'Connection refused'.
- 09:20Check logs: show 'Tomcat started on port(s): 8080 (http)' but then 'Application failed to start'.
- 09:25Run `lsof -i :8080` – no process listed. Tried different port via `server.port=8081` – same behavior.
- 09:30Enable debug logs: `--debug` reveals 'Negative match: DataSourceAutoConfiguration matched because missing DataSource class'.
- 09:35Check `application.properties`: `spring.datasource.url=jdbc:postgresql://localhost:5432/mydb` – database is running? `pg_isready` returns 'accepting connections'.
- 09:40Notice `spring.datasource.platform=postgresql` typo: it should be `postgresql`? Actually correct, but missing `spring.datasource.driver-class-name=org.postgresql.Driver`.
- 09:45Add driver class property, restart. Startup succeeds. Root cause: missing driver class prevents DataSource creation, causing cascading bean failures.
I had just deployed what I thought was a routine build. Jenkins reported success, but when I hit the health endpoint, I got a connection refused. The logs showed Tomcat started successfully, but then the application exited with a generic 'Application failed to start' message. No clear exception beyond that. I spent 10 minutes thinking it was a port conflict, but `lsof` showed nothing on 8080.
I switched to `--debug` and saw the auto-configuration report. The key was a negative match on `DataSourceAutoConfiguration` because the DataSource class was missing. That meant Spring Boot couldn't create the DataSource bean, which caused all beans depending on it to fail. But why? The PostgreSQL driver was in my POM. I checked `application.properties` and realized I had omitted the `spring.datasource.driver-class-name` property. Without it, Spring Boot tries to auto-detect the driver, but sometimes fails silently.
Adding `spring.datasource.driver-class-name=org.postgresql.Driver` fixed it immediately. The lesson: never assume Spring Boot will auto-detect the JDBC driver. Always explicitly set `driver-class-name` when using custom datasources. Also, the `--debug` flag is your best friend – it surfaces the condition evaluation that the normal logs hide.
Root cause
Missing `spring.datasource.driver-class-name` property prevented Spring Boot from creating the DataSource bean, causing all dependent beans to fail and application to exit without a clear error.
The fix
Add `spring.datasource.driver-class-name=org.postgresql.Driver` to application.properties.
The lesson
Always explicitly configure datasource properties, especially the driver class name. Use `--debug` to see the auto-configuration report and identify which conditions failed.
When you pass `--debug` to a Spring Boot application, it prints a 'CONDITIONS EVALUATION REPORT' to the logs. This report lists every auto-configuration class and whether it matched or not. Positive matches mean the conditions to apply that configuration were met; negative matches mean they were not. The report also shows why a condition failed (e.g., missing class, property, or bean).
To generate this report programmatically, use `spring-boot-maven-plugin` with `-Dspring-boot.run.arguments=--debug`. In production, you can enable debug logging for `org.springframework.boot.autoconfigure` by adding `logging.level.org.springframework.boot.autoconfigure=DEBUG` to your properties. This report is the single most valuable diagnostic tool for startup failures.
A common startup failure is 'Port 8080 already in use'. The standard fix is to find and kill the process. But sometimes the process is not shown by `lsof` because it runs as a different user or is a container. Use `sudo lsof -i :8080` or `ss -tlnp | grep 8080` on Linux. On Windows, `netstat -ano | findstr :8080` and then `taskkill /PID <pid> /F`.
Another subtle scenario: Spring Boot might fail to bind to a port even if it's free, because the `server.address` is bound to a specific interface that doesn't exist. Check `server.address` property – if it's set to an IP that isn't available, the application will fail to start. Also, some cloud environments restrict ports; set `server.port=0` to let the OS assign a random port and log it.
BeanCreationException with a message like 'Circular dependency detected' usually arises when two beans depend on each other via constructor injection. Spring Boot detects this at startup and fails. The fix is to break the cycle by using setter injection or `@Lazy` on one of the beans. Use `@Autowired` on a setter instead of constructor, or add `@Lazy` to the constructor parameter.
Another common pattern is missing beans because component scanning doesn't cover the package. Ensure your main application class is in the root package and all components are under it. Use `@ComponentScan(basePackages = "com.example")` explicitly if needed. The auto-configuration report will show negative matches for many beans if scanning is wrong.
If you see `ClassNotFoundException` or `NoClassDefFoundError` during startup, it's often because a required JAR is missing or there's a version conflict. Run `mvn dependency:tree` or `gradle dependencies` to inspect the dependency tree. Look for multiple versions of the same library (e.g., two versions of Jackson) that can cause classloader issues.
Spring Boot's starters are designed to pull in compatible versions, but if you manually add dependencies, you can break that. Use `spring-boot-starter-parent` as the parent POM to get consistent versions. Also, check for exclusions: if you exclude a transitive dependency, you might inadvertently remove a required class. The error message usually points to the missing class; search for it in your JARs with `jar -tf <jar> | grep <classname>`.
Invalid YAML indentation is a silent killer. Spring Boot fails to parse the file and uses default values, which might cause beans to fail later. Use `snakeyaml`'s parser offline: `python -c "import yaml; yaml.load(open('application.yml'))"` or use IDE validation. For properties files, trailing spaces or special characters can cause issues – always use a linter.
Another common mistake is using environment variables with wrong format. Spring Boot relaxes binding, but `SPRING_DATASOURCE_URL` must match the property key exactly if using uppercase conversion. Use `SPRING_DATASOURCE_URL=jdbc:postgresql://...` but remember that some OSes don't allow underscores in env var names – use dots or hyphens accordingly.
Frequently asked questions
How do I enable the auto-configuration report in production?
Add `logging.level.org.springframework.boot.autoconfigure=DEBUG` to your application.properties. This will print the conditions evaluation report at INFO level (since DEBUG is mapped to INFO by default). For more control, you can expose the `/actuator/conditions` endpoint by setting `management.endpoints.web.exposure.include=conditions`.
What does 'Web server failed to start. Port 8080 was already in use.' mean?
It means the Tomcat (or Jetty/Undertow) embedded server could not bind to port 8080 because another process is already using it. Find the process with `lsof -i :8080` (Linux/Mac) or `netstat -ano | findstr :8080` (Windows). Kill it with `kill -9 <PID>` (Linux/Mac) or `taskkill /PID <PID> /F` (Windows). Alternatively, change the port in application.properties with `server.port=8081`.
Why does my Spring Boot app start but never become healthy?
This usually means the application context loaded but a dependent resource (like a database or message broker) is not reachable. Check the health endpoint details: `curl http://localhost:8080/actuator/health` – it might show 'DOWN' with details. Enable debug logging for `org.springframework.boot.actuate` to see health check failures. Common causes: database connection timeout, missing credentials, or network issues.
How to fix 'Parameter 0 of constructor in com.example.MyService required a bean of type ... that could not be found'?
This means Spring could not find a bean of the required type to inject into MyService's constructor. Ensure the dependent bean is annotated with `@Service`, `@Component`, `@Repository`, etc., and that its package is covered by component scanning. If the bean is from a library, you may need to declare it as a `@Bean` in a configuration class. Use `@SpringBootApplication` on a class that includes the scanning base packages.
Can a missing `bootstrap.yml` cause startup failure?
Yes, if your application uses Spring Cloud Config and expects configuration from a remote server. Without `bootstrap.yml` (or `bootstrap.properties`), the bootstrap context is not created, and the application may fail to load properties, leading to missing bean definitions or connection errors. Check if you have `spring-cloud-starter-config` on classpath and a `bootstrap.yml` file with `spring.cloud.config.uri` and other settings.