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

  1. Use the canonical form jdbc:tc:databasetype:tag://host:port/database?query, e.g. jdbc:tc:postgresql:16://localhost:5432/test
  2. Prefer container.getJdbcUrl() over hand-crafting jdbc:tc: URLs
  3. Verify the database type is one the testcontainers JDBC support recognizes
  4. 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

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


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)