{"record":{"id":"9ae8c8b60d833127","repo":"pinpoint-apm/pinpoint","slug":"parse-error-token-is-null-expected-token","errorCode":null,"errorMessage":"parse error. token is null. Expected token='='","messagePattern":"parse error\\. token is null\\. Expected token='='","errorType":"validation","errorClass":"OracleConnectionStringException","httpStatus":null,"severity":"error","filePath":"agent-module/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/parser/OracleNetConnectionDescriptorTokenizer.java","lineNumber":194,"sourceCode":"    public void setPosition(int position) {\n        this.position = position;\n    }\n\n    public void checkStartToken() {\n        Token token = this.nextToken();\n        if (token == null) {\n            throw new OracleConnectionStringException(\"parse error. token is null\");\n        }\n        // We can check by == because the token object is singleton.\n        if (!(token == TOKEN_KEY_START_OBJECT)) {\n            throw new OracleConnectionStringException(\"syntax error. Expected token='(' :\" + token.getToken());\n        }\n    }\n\n    public void checkEqualToken() {\n        Token token = this.nextToken();\n        if (token == null) {\n            throw new OracleConnectionStringException(\"parse error. token is null. Expected token='='\");\n        }\n        // We can check by == because the token object is singleton.\n        if (!(token == TOKEN_EQUAL_OBJECT)) {\n            throw new OracleConnectionStringException(\"Syntax error. Expected token='=' :\" + token.getToken());\n        }\n    }\n\n    public void checkEndToken() {\n        Token token = this.nextToken();\n        if (token == null) {\n            throw new OracleConnectionStringException(\"parse error. token is null. Expected token=')\");\n        }\n        // We can check by == because the token object is singleton.\n        if (!(token == TOKEN_KEY_END_OBJECT)) {\n            throw new OracleConnectionStringException(\"Syntax error. Expected token=')' :\" + token.getToken());\n        }\n    }\n","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/parser/OracleNetConnectionDescriptorTokenizer.java#L176-L212","documentation":"checkEqualToken() consumes the token expected between a key and its value; when nextToken() returns null because the stream ended right after a key, it throws 'parse error. token is null. Expected token='='. The descriptor ended immediately after a key name with no '=' or value.","triggerScenarios":"A descriptor like '(CONNECT_DATA' or '(SERVICE_NAME' where the string ends after the key — the tokenizer is exhausted when checkEqualToken() asks for the '=' token.","commonSituations":"Truncated copy-paste of long descriptors; config parsing that cut the value at '=' or whitespace; template variables that expanded to nothing after the key name.","solutions":["Complete each pair so it reads (KEY=value) with the '=' and value present and the block closed with ')'","Re-copy the descriptor from the original source and diff against the failing URL","Check config preprocessing (quoting, escaping, templating) isn't stripping the '=' and remainder","Fail fast in config validation by pre-parsing the JDBC URL at startup"],"exampleFix":"// before\nString url = \"jdbc:oracle:thin:@(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME\"; // ends after key\n// after\nString url = \"jdbc:oracle:thin:@(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=svc)))\";","handlingStrategy":"validation","validationCode":"static boolean hasKeyValuePairs(String descriptor) {\n    // naive check: no block ends right after an identifier without '='\n    return !descriptor.matches(\".*\\\\([A-Za-z_][A-Za-z0-9_]*$.*\")\n        && descriptor.endsWith(\")\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    parser.parse(url);\n} catch (OracleConnectionStringException e) {\n    log.error(\"Oracle descriptor ended after a key, missing '=': {}\", url, e);\n    throw new ConfigurationException(\"Incomplete KEY=value pair in descriptor\", e);\n}","preventionTips":["Ensure every '(' KEY is followed by =value before the closing ')'","Check that config preprocessing isn't cutting values at '=' or whitespace","Validate the full URL end-to-end (balance and pair check) before startup"],"tags":["jdbc","oracle","url-parsing","truncation"],"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"}