org.postgresql.Driver not found
The error usually surfaces in one of two forms:
java.lang.ClassNotFoundException: org.postgresql.Driver
java.lang.NoClassDefFoundError: org/postgresql/Driver
The first is raised by Class.forName("org.postgresql.Driver") when
the JVM cannot resolve the name; the second is raised by the verifier
when some other class references org.postgresql.Driver and the
class is not available at link time. Both have the same root cause
(the driver class is not visible to the calling classloader) and the
same fix in modern code.
First: do you actually need Class.forName?
Almost certainly not. Since JDBC 4.0 / Java 6, the
DriverManager discovers drivers via the
ServiceLoader
mechanism: every JAR carrying a META-INF/services/java.sql.Driver
file is registered automatically when the JAR is on the classpath.
Every pgJDBC release ships that file in its JAR, containing
org.postgresql.Driver. The
Quick start ServiceLoader note
spells this out next to the modern connection example.
Old tutorials, copy-pasted boilerplate from the Java 1.4 era, and defensive “make sure the driver is loaded” patterns still carry lines like:
Class.forName("org.postgresql.Driver"); // not needed
Connection c = DriverManager.getConnection(url, props);
Delete the Class.forName line. If the driver was already loaded by
the ServiceLoader, this changes nothing. If it was not, you’ll get
No suitable driver found
instead, a more actionable error that points at the real problem
(classpath, shaded JAR, classloader visibility) rather than at the
absent Class.forName call.
If you genuinely cannot remove Class.forName
Some legacy frameworks call Class.forName themselves (the value is
read from a config file) and you can’t change them. The exception
then means exactly what it says: the JVM is asked to load
org.postgresql.Driver and cannot find it. The four causes mirror
those of No suitable driver found
:
- The pgJDBC JAR is not on the classpath. Verify with
mvn dependency:tree,./gradlew dependencies --configuration runtimeClasspath, or by inspecting the runtime classpath the launcher passes tojava. - The JAR is on the classpath but in a different classloader.
Common in OSGi, JPMS-with-classpath-mix, and application servers
where the driver lives in a shared loader and the calling code
lives in a child.
Class.forNameresolves through the caller’s classloader by default; if the loader chain does not reach the JAR, the class is invisible.- For the three-argument form
Class.forName(name, true, classLoader), the loader you pass is the one that searches. - The cleanest fix is to lift the JAR to a classloader visible to
the caller.
PGSimpleDataSourcecan help with ServiceLoader visibility becauseBaseDataSourceexplicitly loadsorg.postgresql.Driver, but its connection path still goes throughDriverManager.
- For the three-argument form
- The class was stripped by a shading minimiser. Maven Shade
Plugin’s
minimizeJarand similar tools may decide thatorg.postgresql.Driveris unreachable (there are no direct byte-code references to it;ServiceLoaderfinds it via reflection) and drop it from the final artifact. Either disableminimizeJarfor this artifact or add an explicit keep rule (<filter><artifact>org.postgresql:postgresql</artifact><includes><include>**</include></includes></filter>). - A
NoClassDefFoundErroron a different class. If the message isNoClassDefFoundError: org/postgresql/util/...(anything other thanDriveritself), the driver class loaded but another class needed by that code path did not. For example, SSPI requireswaffle-jnato be available, and custom source-distribution or shaded builds must keep the shaded SCRAM classes and OSGi support classes they use.
Related
- No suitable driver found
:
the
DriverManager-side variant of the same root issue, with more detail on shaded JARs and classloader visibility. - Quick start
: the
Maven / Gradle dependency declaration and the
ServiceLoader-vs-Class.forNamenote. - DataSource and JNDI
:
PGSimpleDataSourceexplicitly loads the pgJDBC driver before requesting a connection throughDriverManager.