{"record":{"id":"5724f7cc9baf1b25","repo":"pinpoint-apm/pinpoint","slug":"parsing-error-expected-token-eof-token-null","errorCode":null,"errorMessage":"parsing error. expected token:'EOF' token:null","messagePattern":"parsing error\\. expected token:'EOF' token:null","errorType":"validation","errorClass":"OracleConnectionStringException","httpStatus":null,"severity":"error","filePath":"agent-module/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/parser/OracleNetConnectionDescriptorParser.java","lineNumber":69,"sourceCode":"        } else {\n            throw new IllegalArgumentException(\"invalid oracle jdbc url. expected token:(\" + THIN + \" or \" + OCI + \") url:\" + url);\n        }\n\n        // skip thin string\n        this.tokenizer.setPosition(position);\n\n        this.tokenizer.parse();\n        KeyValue<?> keyValue = parseKeyValue();\n\n        checkEof();\n\n        return keyValue;\n    }\n\n    private void checkEof() {\n        Token eof = this.tokenizer.nextToken();\n        if (eof == null) {\n            throw new OracleConnectionStringException(\"parsing error. expected token:'EOF' token:null\");\n        }\n        if (eof != OracleNetConnectionDescriptorTokenizer.TOKEN_EOF_OBJECT) {\n            throw new OracleConnectionStringException(\"parsing error. expected token:'EOF' token:\" + eof);\n        }\n    }\n\n    public DriverType getDriverType() {\n        return driverType;\n    }\n\n    private int nextPosition(String driverUrl) {\n        final int thinLength = driverUrl.length();\n        if (normalizedUrl.startsWith(\":@\", thinLength)) {\n            return thinLength + 2;\n        } else if(normalizedUrl.startsWith(\"@\", thinLength)) {\n            return thinLength + 1;\n        } else {\n            throw new OracleConnectionStringException(\"invalid oracle jdbc url:\" + driverUrl);","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/parser/OracleNetConnectionDescriptorParser.java#L51-L87","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nString url = \"jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc))\"; // missing final ')'\n// after\nString url = \"jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc)))\";","handlingStrategy":"validation","validationCode":"static boolean isBalanced(String url) {\n    int depth = 0;\n    for (char c : url.toCharArray()) {\n        if (c == '(') depth++;\n        else if (c == ')') depth--;\n        if (depth < 0) return false;\n    }\n    return depth == 0;\n}\n// call before use: if (!isBalanced(jdbcUrl)) failFast(...);","typeGuard":"boolean isDescriptorUrl(String url) {\n    return url != null && url.startsWith(\"jdbc:oracle:thin:@(\") && url.endsWith(\")\") && isBalanced(url);\n}","tryCatchPattern":"try {\n    DataSource ds = driver.connect(url, props);\n} catch (OracleConnectionStringException e) {\n    log.error(\"Malformed Oracle descriptor URL (check parentheses): {}\", url, e);\n    throw new ConfigurationException(\"Invalid jdbc url\", e);\n}","preventionTips":["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"],"tags":["jdbc","oracle","url-parsing","syntax"],"backgroundTag":"invalid-url-format","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}