Spring Boot · advanced
Spring ApplicationContextException: isolate startup infrastructure failure
Spring ApplicationContextException indicates that the Spring Boot application context failed to start a required infrastructure component (DataSource, JPA EntityManagerFactory, embedded web server, MessageSource, scheduling TaskScheduler, etc.). This guide focuses on isolating which dependency or bean blocked refresh, separating infrastructure failure from ordinary bean wiring errors.
The symptoms
- •The JVM exits during startup with a stack trace whose root cause is org.springframework.context.ApplicationContextException (often wrapped by UnsatisfiedDependencyException or BeanCreationException).
- •SpringApplication.run() never returns; the banner prints but context refresh halts before the embedded server reports an open port.
- •A specific infrastructure bean fails to initialize: Hibernate EntityManagerFactory, Tomcat connector, DataSource pool, JMS connection factory, Quartz scheduler, Flyway/Liquibase runner, or MessageSource.
- •Startup logs show a deferred "APPLICATION FAILED TO START" message with an explicit description (for example, "Unable to start EmbeddedWebApplicationContext" or "Failed to start bean 'documentationPluginsBootstrapper'").
- •Re-running the same jar produces the same failure at the same bean, even after a clean local build, pointing to a non-deterministic infrastructure reachability problem rather than a code defect.
Likely causes
- •An external infrastructure dependency (database, message broker, LDAP, SMTP) is unreachable, refusing connections, or has credentials that no longer permit the configured role.
- •Database migration tooling (Flyway, Liquibase) or JPA/Hibernate initialization detected incompatible schema state and aborted EntityManagerFactory creation.
- •The embedded web server (Tomcat, Jetty, Undertow) could not bind its connector — port reserved by another process, missing SSL material, or unsupported protocol handler.
- •An auto-configured component declared a hard requirement on a property that is missing, empty, or syntactically invalid (for example, spring.datasource.url, spring.flyway.enabled, server.port).
- •A bean class on the classpath registers an @Bean producer whose dependency graph crosses an unbound @ConfigurationProperties prefix, causing refresh to fail before the regular bean wiring phase.
- •A scheduling or async executor infrastructure bean (TaskScheduler, ThreadPoolTaskExecutor) could not satisfy its pool sizing or rejection policy constraints declared in configuration.
First ten minutes
- 01Capture the full stack trace and the SpringApplicationStartup summary printed just before the failure; record the failed bean name and the application version, build artifact, and JVM arguments.
- 02Identify whether the exception is thrown during context refresh (before web server starts) versus during web server start itself; this determines whether the failure belongs to infrastructure wiring or to the web layer.
- 03Read the SpringApplicationStartup timings or the timing messages around "Started ... in ... seconds"; if the line is missing, refresh never completed.
- 04Check the operating system listener state for every host/port the application must reach at startup (database, broker, LDAP, SMTP) using read-only network probes; mark any that refuse or time out as suspects.
- 05Inspect the active configuration profile and external config sources (application.yml, environment variables, config server) for the property named in the exception message; confirm value, type, and resolution order.
- 06Decide between an infrastructure reachability problem and a configuration mismatch before touching code; this branch determines the next investigation.
Evidence to collect
- •The exact ApplicationContextException message plus the immediately preceding "Description of the problem" paragraph Spring prints with action recommendations.
- •The failed bean name and its declaring class, usually visible in BeanCreationException.getBeanName() or EmbeddedServletContainerException-style wrappers.
- •Active Spring profiles, resolved property sources, and the value of the property explicitly named in the failure message.
- •Connectivity state for each external dependency at the moment of failure (TCP reachability, TLS handshake result, authentication response, schema/version banner).
- •Process and port inventory on the host to detect whether another process owns a port the embedded server tried to bind.
- •Build artifact coordinates and dependency tree to confirm the auto-configuration version matches what the failure stack references.
Where to look
- •Bootstrap logs printed by SpringApplication before the exception, specifically the section that lists "The following profiles are active" and the auto-configuration report (debug level).
- •Standard error stream lines surrounding the ApplicationContextException; Spring prints a human-readable "Description" block immediately before the cause chain.
- •Property sources in precedence order: command-line arguments, OS environment variables, application-{profile}.yml/yaml/properties inside the classpath or config/ directory, and remote config server responses.
- •External dependency logs reachable for the startup window: JDBC driver handshake messages, broker connection acknowledgements, LDAP bind results, SMTP EHLO responses.
- •Container/orchestrator plumbing when the process runs under one: readiness probe logs, sidecar startup order, mounted secret values, and init container exit status.
- •The Spring Boot reference documentation page that lists conditions for each auto-configuration class involved (DataSourceAutoConfiguration, HibernateJpaAutoConfiguration, FlywayAutoConfiguration, EmbeddedWebServerFactoryCustomizerAutoConfiguration).
Diagnostic steps
- 01Parse the root cause class name; if it extends org.springframework.beans.FatalBeanException or org.springframework.boot.web.server.WebServerException, the failure is infrastructure rather than ordinary bean wiring.
- 02Walk the cause chain upward from ApplicationContextException to identify the leaf IOException, SQLException, RuntimeException, or UnsatisfiedDependencyException that names the missing piece.
- 03For each external dependency named in the chain, run a read-only TCP reachability probe and capture the latency and refusal state; compare with the application's configured timeout.
- 04Enable org.springframework.boot.autoconfigure logging at DEBUG for the duration of one restart and capture the conditions evaluation report; cross-reference positive matches against the missing bean.
- 05Boot the same jar with a minimal profile (for example, --spring.profiles.active=diag --spring.autoconfigure.exclude=...) that disables one auto-configuration at a time to bisect the failing module.
- 06Inspect server.port, management.server.port, and any server.tomcat.remoteip properties to confirm no two listeners collide on the same interface and port range.
- 07When schema migration is involved, query the migration tool's history table with a read-only statement to see whether the recorded checksum matches the packaged migration scripts.
Common mistakes
- •Treating ApplicationContextException as a generic wiring bug and restarting the JVM repeatedly without inspecting the cause chain — this masks intermittent infrastructure outages.
- •Editing application.yml to comment out the failing property, which suppresses the bean instead of fixing it and leaves the running artifact unable to serve traffic.
- •Assuming the embedded server failed because of an application code bug when the cause is a port collision with another Spring Boot instance or a sidecar process.
- •Trusting "works locally" as evidence that production must be misconfigured; reachability, credentials, and schema drift are the most frequent discrepancies.
- •Reading only the top frame of the stack trace; Spring's refresh failure wraps the real cause several frames down, often inside an auto-configured factory method.
- •Mutating a shared schema or config server to "make it start" rather than rolling forward the application's required schema or configuration contract.
Safe fixes
- •If the cause is a refused external connection, restore reachability (restart the dependency, correct DNS, open the security group) and re-run the application against the same configuration; confirm the new banner reports "Started ... in ... seconds".
- •If the cause is a missing required property, set the property to a value derived from the dependency's documented contract rather than a placeholder, then re-run with the same profile.
- •If the cause is a port collision, change server.port on the loser side and verify with the operating system that the new listener enters LISTEN state before routing traffic to the instance.
- •If the cause is a Flyway/Liquibase checksum mismatch, decide intentionally between repairing checksums (only when the migration is known-equivalent) and rolling forward the schema; do not delete the history table.
- •If the cause is an auto-configuration that should not apply, narrow the exclusion list with --spring.autoconfigure.exclude and document the reason in the deployment manifest.
- •After any change, restart once with -Dlogging.level.org.springframework.boot.autoconfigure=DEBUG to capture the conditions evaluation report and confirm the bean graph matches expectations.
Prove the fix
- 01The SpringApplication log prints "Started Application in <duration> seconds" and no ApplicationContextException follows; a readiness probe (configured generically against the application's health endpoint) returns 200 within the documented timeout.
- 02The auto-configuration conditions report (DEBUG) lists the previously failing bean as positive-matched against the intended configuration sources, with no unmatched @ConditionalOnMissingBean surprises.
- 03A scripted health check exercised against the production listener receives an HTTP 200 from the application's documented liveness/readiness route; this is repeated across two consecutive restarts to rule out startup flakiness.
- 04External dependency logs show the application's startup connection succeeding — JDBC handshake completed, broker session established, LDAP bind returned success, SMTP EHLO accepted — and no retry storm is observed.
- 05The startup duration recorded in SpringApplicationStartup timings is within the documented baseline band; subsequent warm starts do not regress, which proves no bean is initializing lazily on first request.
Prevention and next steps
- •Treat every required infrastructure dependency as a startup health gate: define an explicit readiness probe that fails closed until the dependency has been contacted successfully during refresh.
- •Pin auto-configuration behavior with explicit @ConditionalOnProperty values for optional modules, so missing properties fail predictably rather than discovering the gap only at refresh time.
- •Keep configuration externalized through a documented precedence order; record the resolved value of each critical property in startup logs at INFO level for post-incident review.
- •Add a smoke test that boots the full ApplicationContext against a stubbed or containerized dependency set; run it in CI before any release artifact is promoted.
- •When introducing a new auto-configured module, write a targeted exclusion recipe and store it alongside the configuration so an operator can disable the module without code changes.
Safe commands and checks
java -jar <app.jar> --logging.level.org.springframework.boot.autoconfigure=DEBUG --spring.profiles.active=diag 2>&1 | tee /tmp/startup.log java -jar <app.jar> --debug --spring.application.admin.enabled=true 2>&1 | grep -E 'Started Application|APPLICATION FAILED|Action:' java -jar <app.jar> --spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration 2>&1 | head -n 200 java -jar <app.jar> --server.port=<port> 2>&1 | grep -E 'Tomcat started|Web server failed|Exception' java -Dlogging.level.org.springframework.context=DEBUG -jar <app.jar> 2>&1 | grep -E 'Bean .* of type|positive matches|negative matches' java -jar <app.jar> --spring.flyway.validate-on-migrate=false --spring.flyway.baseline-on-migrate=true 2>&1 | grep -E 'Successfully applied|Validation failed|Migration' java -jar <app.jar> --management.endpoint.health.probes.enabled=true --management.endpoint.health.group.readiness.include=readinessState 2>&1 | grep -E 'LivenessState|ReadinessState|Break' ps -o pid,command -p <pid> && ss -ltnp '( sport = :<port> )'