pinpoint-apm/pinpoint · error · OracleConnectionStringException

Syntax error. lookAheadToken is null

Error message

Syntax error. lookAheadToken is null

What it means

parseKeyValue() loops on tokenizer.lookAheadToken(); when it returns null the token stream ran out before a value, key start '(' or key end ')' was seen, so the recursive-descent parser hit abnormal termination and throws. This is a truncated descriptor: the grammar expects more tokens than the input provides.

Source

Thrown at agent-module/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/parser/OracleNetConnectionDescriptorParser.java:110

        // start
        this.tokenizer.checkStartToken();


        // key
        Token literalToken = this.tokenizer.getLiteralToken();
        KeyValue.Builder keyValue = new KeyValue.Builder(literalToken.getToken());

        // =
        this.tokenizer.checkEqualToken();

        // value compare reduce
        boolean nonTerminalValue = false;
        while(true) {
            final Token token = this.tokenizer.lookAheadToken();
            if (token == null) {
                // Abnormal termination.
                throw new OracleConnectionStringException("Syntax error. lookAheadToken is null");
            }
            if (token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_KEY_START) {
                nonTerminalValue = true;
                KeyValue child = parseKeyValue();
                keyValue.addKeyValueList(child);

                // if next token is ')', value is completed.
                Token endCheck = this.tokenizer.lookAheadToken();
                if (endCheck == OracleNetConnectionDescriptorTokenizer.TOKEN_KEY_END_OBJECT) {
                    this.tokenizer.nextPosition();
                    return keyValue.build();
                }
            } else if(token.getType() == OracleNetConnectionDescriptorTokenizer.TYPE_LITERAL) {
                if (nonTerminalValue) {
                    throw new OracleConnectionStringException("Syntax error. expected token:'(' or ')' :" + token.getToken());
                }
                // We already have checked current token by lookAheadToken(). Proceed to next token.
                this.tokenizer.nextPosition();

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Restore the missing value/closing structure so every (KEY=VALUE) pair is complete and balanced
  2. Compare the URL against the original tnsnames.ora entry and re-copy it intact
  3. Enable quoting of the descriptor in config files (YAML/single quotes) so special characters aren't stripped
  4. Add a startup validation step that calls the parser on the configured URL and fails fast with the full string logged

Example fix

// before
String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db)(PORT=1521))(CONNECT_DATA"; // truncated
// 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 isCompleteDescriptor(String url) {
    if (url == null) return false;
    String d = url.substring(url.indexOf('@') + 1);
    return d.startsWith("(") && d.endsWith(")") && isBalanced(d);
}

Try / catch

try {
    parser.parse(url);
} catch (OracleConnectionStringException e) {
    log.error("Oracle descriptor truncated (missing value or ')'): {}", url, e);
    throw new ConfigurationException("Incomplete oracle connection descriptor", e);
}

Prevention

When it happens

Trigger: A descriptor where a key's value section is missing entirely, e.g. '(KEY=)' followed by end-of-input, or '(CONNECT_DATA' ending the string — lookAheadToken() exhausts the stream inside the while(true) loop.

Common situations: Copy-paste truncation of a long tnsnames entry; config templating that dropped everything after a variable; an editor or YAML parser stripping the trailing ')' characters or quoting the value away.

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


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/f2cf0c7ce6ab6f9d. Report an issue: GitHub.