testcontainers/testcontainers-java · error · IllegalArgumentException
The '?' character must be included
Error message
The '?' character must be included
What it means
constructUrlForConnection(String queryString) appends an optional query string to the base JDBC URL, and documents/enforces that a non-empty query string must start with '?'. A bare 'key=value' string without the leading question mark triggers this IllegalArgumentException to prevent malformed URLs.
Solutions
- Prefix the query string with '?', e.g. createConnection("?ssl=true")
- Pass an empty string if no parameters are needed
- Build the query via a helper that always prepends '?' when non-empty
Example fix
// before
container.createConnection("ssl=true&connectTimeout=30");
// after
container.createConnection("?ssl=true&connectTimeout=30"); Defensive patterns
Strategy: validation
Validate before calling
String qs = params.isEmpty() ? "" : "?" + String.join("&", params); Type guard
static String ensureQueryString(String s) { return (s == null || s.isEmpty() || s.startsWith("?")) ? s : "?" + s; } Try / catch
try { url = container.createConnection(qs); } catch (IllegalArgumentException e) { if (e.getMessage().contains("'?' character")) { /* re-call with '?'+qs */ } } Prevention
- Never pass raw key=value pairs without the leading '?'
- Use a helper that normalizes empty and non-empty query strings
When it happens
Trigger: Calling createConnection("key=value") (or url(...) paths) with a query string lacking the leading '?' character.
Common situations: Manually building parameter strings like 'ssl=true' without '?'; template concatenation that strips the question mark; copying URL fragments from documentation that include the base URL's '?' already.
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
- JDBC URL matches jdbc:tc: prefix but the database or tag…
- 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/0e988706b9f4abfc.
Report an issue: GitHub.
Appendix: source
Thrown at modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java:316
/**
* Template method for constructing the JDBC URL to be used for creating {@link Connection}s.
* This should be overridden if the JDBC URL and query string concatenation or URL string
* construction needs to be different to normal.
*
* @param queryString query string parameters that should be appended to the JDBC connection URL.
* The '?' character must be included
* @return a full JDBC URL including queryString
*/
protected String constructUrlForConnection(String queryString) {
String baseUrl = getJdbcUrl();
if ("".equals(queryString)) {
return baseUrl;
}
if (!queryString.startsWith("?")) {
throw new IllegalArgumentException("The '?' character must be included");
}
return baseUrl.contains("?")
? baseUrl + QUERY_PARAM_SEPARATOR + queryString.substring(1)
: baseUrl + queryString;
}
protected String constructUrlParameters(String startCharacter, String delimiter) {
return constructUrlParameters(startCharacter, delimiter, StringUtils.EMPTY);
}
protected String constructUrlParameters(String startCharacter, String delimiter, String endCharacter) {
String urlParameters = "";
if (!this.urlParameters.isEmpty()) {
String additionalParameters =
this.urlParameters.entrySet().stream().map(Object::toString).collect(Collectors.joining(delimiter));
urlParameters = startCharacter + additionalParameters + endCharacter;
}View on GitHub (pinned to 8e549514e3)