pinpoint-apm/pinpoint · error · OracleConnectionStringException
parsing error. expected token:'EOF' token:null
Error message
parsing error. expected token:'EOF' token:null
What it means
OracleNetConnectionDescriptorParser.parse() finishes by consuming the remaining tokens and expects the very next token to be the tokenizer's singleton EOF token. When tokenizer.nextToken() returns null (the token stream is exhausted before the parser finishes) checkEof() throws this OracleConnectionStringException. It means the connection descriptor string ended mid-structure, typically from unbalanced parentheses.
Source
Thrown at agent-module/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/parser/OracleNetConnectionDescriptorParser.java:69
} else {
throw new IllegalArgumentException("invalid oracle jdbc url. expected token:(" + THIN + " or " + OCI + ") url:" + url);
}
// skip thin string
this.tokenizer.setPosition(position);
this.tokenizer.parse();
KeyValue<?> keyValue = parseKeyValue();
checkEof();
return keyValue;
}
private void checkEof() {
Token eof = this.tokenizer.nextToken();
if (eof == null) {
throw new OracleConnectionStringException("parsing error. expected token:'EOF' token:null");
}
if (eof != OracleNetConnectionDescriptorTokenizer.TOKEN_EOF_OBJECT) {
throw new OracleConnectionStringException("parsing error. expected token:'EOF' token:" + eof);
}
}
public DriverType getDriverType() {
return driverType;
}
private int nextPosition(String driverUrl) {
final int thinLength = driverUrl.length();
if (normalizedUrl.startsWith(":@", thinLength)) {
return thinLength + 2;
} else if(normalizedUrl.startsWith("@", thinLength)) {
return thinLength + 1;
} else {
throw new OracleConnectionStringException("invalid oracle jdbc url:" + driverUrl);View on GitHub (pinned to 744c3d3075)
Solutions
- Count the parentheses in the descriptor and add the missing ')' for every unclosed '(' before the end of the URL
- Use a complete valid descriptor, e.g. jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc)))
- If you only need host/port/db, switch to the simple URL form jdbc:oracle:thin:@host:1521:SID to avoid descriptor parsing entirely
- Log the full driverUrl at parse failure and compare character-by-character with a known-good descriptor
Example fix
// before String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc))"; // missing final ')' // after String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc)))";
Defensive patterns
Strategy: validation
Validate before calling
static boolean isBalanced(String url) {
int depth = 0;
for (char c : url.toCharArray()) {
if (c == '(') depth++;
else if (c == ')') depth--;
if (depth < 0) return false;
}
return depth == 0;
}
// call before use: if (!isBalanced(jdbcUrl)) failFast(...); Type guard
boolean isDescriptorUrl(String url) {
return url != null && url.startsWith("jdbc:oracle:thin:@(") && url.endsWith(")") && isBalanced(url);
} Try / catch
try {
DataSource ds = driver.connect(url, props);
} catch (OracleConnectionStringException e) {
log.error("Malformed Oracle descriptor URL (check parentheses): {}", url, e);
throw new ConfigurationException("Invalid jdbc url", e);
} Prevention
- Validate parenthesis balance of descriptor URLs at config load time
- Prefer the simple jdbc:oracle:thin:@host:port:SID form when no advanced options are needed
- Keep descriptors on one line in config files and re-copy from tnsnames.ora rather than hand-editing
When it happens
Trigger: Parsing a jdbc:oracle:thin:@(DESCRIPTION=... style URL whose token stream ends before parse() reaches its terminal checkEof() call — e.g. a descriptor with an unclosed '(' so parseKeyValue recursion consumes all tokens and nextToken() returns null.
Common situations: Copy-pasting a truncated or hand-edited tnsnames-style descriptor into the JDBC URL; a config value wrapped or split so the closing ')' characters are lost; programmatically building a descriptor with a missing closing paren per nested key.
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
- Syntax error. expected token:'(' or ')' :<token>
- syntax error. Expected token='(' :<token>
- description node not found
- description_list node not found
- invalid oracle jdbc url. expected token:(thin or oci) url:<u
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/5724f7cc9baf1b25.
Report an issue: GitHub.