testcontainers/testcontainers-java · error · IllegalArgumentException
JDBC URL matches jdbc:tc: prefix but the database or tag…
Error message
JDBC URL matches jdbc:tc: prefix but the database or tag name could not be identified
What it means
ConnectionUrl.parseUrl() matches jdbc:tc: URLs against a pattern to extract database type, tag, and query parts. If the URL has the jdbc:tc: prefix but matches neither the standard nor the Oracle pattern, the database type cannot be identified and this IllegalArgumentException is thrown.
Solutions
- Use the canonical form jdbc:tc:databasetype:tag://host:port/database?query, e.g. jdbc:tc:postgresql:16://localhost:5432/test
- Prefer container.getJdbcUrl() over hand-crafting jdbc:tc: URLs
- Verify the database type is one the testcontainers JDBC support recognizes
- Check for typos or extra characters (spaces, wrong separators) in the URL
Example fix
// before
ConnectionUrl.newInstance("jdbc:tc:postgres:16//localhost/db");
// after
ConnectionUrl.newInstance("jdbc:tc:postgresql:16://localhost:5432/db"); Defensive patterns
Strategy: validation
Validate before calling
static boolean isValidJdbcTcUrl(String url) { return url != null && url.matches("jdbc:tc:[a-z0-9]+(:[\w.-]+)?(:.*)?//.+"); } Try / catch
try { ConnectionUrl url = ConnectionUrl.newInstance(jdbcUrl); } catch (IllegalArgumentException e) { /* fix URL to jdbc:tc:type:tag://host/db form */ } Prevention
- Prefer container.getJdbcUrl() over hand-written jdbc:tc: URLs
- Follow the documented pattern jdbc:tc:databasetype:tag://host:port/database
- Validate generated URLs in CI with a regex test
When it happens
Trigger: Calling new ConnectionUrl("jdbc:tc:...", ...) (or via the jdbc:tc: driver) with a malformed URL, e.g. missing database type (jdbc:tc://host/db), unsupported type spelling, or garbled query string.
Common situations: Typos in the database type segment (jdbc:tc:postgress:16://...); missing the //host part; hand-built URLs missing the image tag separator; URLs generated by string concatenation gone wrong.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- The '?' character must be included
- Can't find valid driver class for OceanBase
- Container is started, but cannot be accessed by
- Could create JDBC statement
- Could not create new connection
AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12).
Data as JSON: /api/errors/19dc1aae20296be9.
Report an issue: GitHub.
Appendix: source
Thrown at modules/jdbc/src/main/java/org/testcontainers/jdbc/ConnectionUrl.java:94
/**
* This method applies various REGEX Patterns to parse the URL associated with this instance.
* This is called from a @{@link ConnectionUrl#newInstance(String)} static factory method to create immutable instance of
* {@link ConnectionUrl}.
* To avoid mutation after class is instantiated, this method should not be publicly accessible.
*/
private void parseUrl() {
/*
Extract from the JDBC connection URL:
* The database type (e.g. mysql, postgresql, ...)
* The docker tag, if provided.
* The URL query string, if provided
*/
Matcher urlMatcher = Patterns.URL_MATCHING_PATTERN.matcher(this.getUrl());
if (!urlMatcher.matches()) {
//Try for Oracle pattern
urlMatcher = Patterns.ORACLE_URL_MATCHING_PATTERN.matcher(this.getUrl());
if (!urlMatcher.matches()) {
throw new IllegalArgumentException(
"JDBC URL matches jdbc:tc: prefix but the database or tag name could not be identified"
);
}
}
databaseType = urlMatcher.group("databaseType");
imageTag = Optional.ofNullable(urlMatcher.group("imageTag"));
//String like hostname:port/database name, which may vary based on target database.
//Clients can further parse it as needed.
dbHostString = urlMatcher.group("dbHostString");
//In case it matches to the default pattern
Matcher dbInstanceMatcher = Patterns.DB_INSTANCE_MATCHING_PATTERN.matcher(dbHostString);
if (dbInstanceMatcher.matches()) {
databaseHost = Optional.ofNullable(dbInstanceMatcher.group("databaseHost"));
databasePort = Optional.ofNullable(dbInstanceMatcher.group("databasePort")).map(Integer::valueOf);
databaseName = Optional.of(dbInstanceMatcher.group("databaseName"));View on GitHub (pinned to 8e549514e3)