{"record":{"id":"9b762436da806b21","repo":"pinpoint-apm/pinpoint","slug":"syntax-error-expected-token-or-token","errorCode":null,"errorMessage":"Syntax error. expected token:'(' or ')' :<token>","messagePattern":"Syntax error\\. expected token:'\\(' or '\\)' :<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/OracleNetConnectionDescriptorParser.java","lineNumber":125,"sourceCode":"            final Token token = this.tokenizer.lookAheadToken();\n            if (token == null) {\n                // Abnormal termination.\n                throw new OracleConnectionStringException(\"Syntax error. lookAheadToken is null\");\n            }\n            if (token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_KEY_START) {\n                nonTerminalValue = true;\n                KeyValue child = parseKeyValue();\n                keyValue.addKeyValueList(child);\n\n                // if next token is ')', value is completed.\n                Token endCheck = this.tokenizer.lookAheadToken();\n                if (endCheck == OracleNetConnectionDescriptorTokenizer.TOKEN_KEY_END_OBJECT) {\n                    this.tokenizer.nextPosition();\n                    return keyValue.build();\n                }\n            } else if(token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_LITERAL) {\n                if (nonTerminalValue) {\n                    throw new OracleConnectionStringException(\"Syntax error. expected token:'(' or ')' :\" + token.getToken());\n                }\n                // We already have checked current token by lookAheadToken(). Proceed to next token.\n                this.tokenizer.nextPosition();\n\n                keyValue.setValue(token.getToken());\n                this.tokenizer.checkEndToken();\n                return keyValue.build();\n            } else if(token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_KEY_END){\n                this.tokenizer.nextPosition();\n                // This could happen if value is empty.\n                // Does it allow empty value?\n                return keyValue.build();\n            } else {\n                // Cannot reach here because we checked all those possible cases, START, END and LITERAL.\n                // Adding new token type could cause error.\n                // In case of syntax error, EOF can come to here. \n                throw new OracleConnectionStringException(\"Syntax error. \" + token.getToken());\n            }","sourceCodeStart":107,"sourceCodeEnd":143,"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#L107-L143","documentation":"Inside parseKeyValue(), after a key has already been reduced (nonTerminalValue is true — a nested child key-value was parsed), a LITERAL token appears where only '(' or ')' is grammatically valid, so the parser throws. It means two sibling values or a value after a nested block without an '=' — structurally ambiguous input.","triggerScenarios":"A descriptor like (CONNECT_DATA=(SERVICE_NAME=svc)extra) or (KEY=a=b): after parsing the nested child or the first literal, a stray literal token arrives and hits the nonTerminalValue branch.","commonSituations":"Hand-edited descriptors with duplicated values; missing '=' between key and value so the key text is treated as a literal after a nested block; typos like (HOST=db PORT=1521) missing the inner parentheses and '='.","solutions":["Rewrite the offending segment so every attribute is a parenthesized (NAME=value) pair","Check for a missing '=' between key and value and add it","Remove the stray literal token that follows the nested child block","Validate the descriptor with a tnsnames parser or try connecting with plain sqlplus using the same descriptor to confirm syntax"],"exampleFix":"// before\nString url = \"jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc)SID=x))\";\n// after\nString url = \"jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=svc)(SID=x)))\";","handlingStrategy":"validation","validationCode":"// every attribute must be a parenthesized (KEY=value) pair\nstatic boolean onlyParenthesizedPairs(String descriptor) {\n    java.util.Deque<Character> st = new java.util.ArrayDeque<>();\n    for (char c : descriptor.toCharArray()) {\n        if (c == '(') st.push(c);\n        else if (c == ')') { if (st.isEmpty()) return false; st.pop(); }\n    }\n    return st.isEmpty();\n}","typeGuard":null,"tryCatchPattern":"try {\n    parser.parse(url);\n} catch (OracleConnectionStringException e) {\n    log.error(\"Oracle descriptor has a stray literal where '(' or ')' expected: {}\", url, e);\n    throw new ConfigurationException(\"Descriptor syntax: use (KEY=value) pairs\", e);\n}","preventionTips":["Ensure each key is wrapped as (KEY=value) with '=' between name and value","Do not place bare tokens after a nested child block","Test the descriptor with sqlplus before deploying it in the JDBC URL"],"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-14T11:17:12.474Z"}