hibernate/hibernate-orm · error · PersistenceException

Unable to obtain input stream from [{}]

Error message

Unable to obtain input stream from [{}]

What it means

Thrown by PersistenceXmlParser.loadUrlWithJaxb() as a PersistenceException when URL.openConnection() succeeded but connection.getInputStream() raised an IOException while reading a persistence.xml resource. The resource URL resolved, but the actual stream could not be opened - the connection to the resource broke at read time. The resource name is included in the message.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceXmlParser.java:326

			}
			throw new PersistenceException( "Unknown persistence unit transaction type : " + value );
		}
	}

	private JaxbPersistenceImpl loadUrlWithJaxb(URL xmlUrl) {
		final String resourceName = xmlUrl.toExternalForm();
		try {
			var connection = xmlUrl.openConnection();
			// avoid JAR locking on Windows and Tomcat
			connection.setUseCaches( false );
			try ( var inputStream = connection.getInputStream() ) {
				return new ConfigurationBinder( classLoaderService )
						.bind( new StreamSource( inputStream ),
								new Origin( SourceType.URL, resourceName ) )
						.getRoot();
			}
			catch (IOException e) {
				throw new PersistenceException( "Unable to obtain input stream from [" + resourceName + "]", e );
			}
		}
		catch (IOException e) {
			throw new PersistenceException( "Unable to access [" + resourceName + "]", e );
		}
	}

}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Verify the resource named in the message exists and is readable at bootstrap time (open it manually from the same classloader).
  2. Rebuild/redeploy the artifact to eliminate a corrupted or truncated jar.
  3. On Windows/Tomcat, ensure no process locks the jar (setUseCaches(false) is already applied by Hibernate) and stop parallel redeployments during boot.
  4. If the file lives on a remote URL, check network availability and server logs for the refused read.

Example fix

// before: jar replaced while app boots
// after: deploy atomically - build the war fully, then swap it in one step
// e.g. cp app.war.new tmp/ && mv tmp/app.war.new webapps/app.war
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-open the descriptor from the same classloader before boot
URL url = Thread.currentThread().getContextClassLoader().getResource("META-INF/persistence.xml");
if (url == null) throw new IllegalStateException("persistence.xml not found");
try (InputStream in = url.openConnection().getInputStream()) { in.read(); } // fail with your own error

Try / catch

catch (PersistenceException e) {
    if (e.getMessage() != null && e.getMessage().contains("Unable to obtain input stream")) {
        log.error("persistence.xml unreadable (locked/removed/corrupt jar): {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Opening the persistence.xml URL during parsing where the jar/file was deleted, swapped, or locked between URL resolution and stream read; a jar entry that reports a size but cannot be read (corrupt zip); permission denied on the file; connection refused for an http-hosted descriptor.

Common situations: Hot redeploy/repackaging on Windows where the old jar is locked or removed mid-boot; exploded deployments whose META-INF/persistence.xml permissions changed; partially uploaded or corrupted jar files; Tomcat/JBoss wars being modified while Hibernate scans them.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/abf5fe22a1b3d316. Report an issue: GitHub.