pinpoint-apm/pinpoint · error · OracleConnectionStringException

parse error. token is null. Expected token='='

Error message

parse error. token is null. Expected token='='

What it means

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.

Source

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

    public void setPosition(int position) {
        this.position = position;
    }

    public void checkStartToken() {
        Token token = this.nextToken();
        if (token == null) {
            throw new OracleConnectionStringException("parse error. token is null");
        }
        // We can check by == because the token object is singleton.
        if (!(token == TOKEN_KEY_START_OBJECT)) {
            throw new OracleConnectionStringException("syntax error. Expected token='(' :" + token.getToken());
        }
    }

    public void checkEqualToken() {
        Token token = this.nextToken();
        if (token == null) {
            throw new OracleConnectionStringException("parse error. token is null. Expected token='='");
        }
        // We can check by == because the token object is singleton.
        if (!(token == TOKEN_EQUAL_OBJECT)) {
            throw new OracleConnectionStringException("Syntax error. Expected token='=' :" + token.getToken());
        }
    }

    public void checkEndToken() {
        Token token = this.nextToken();
        if (token == null) {
            throw new OracleConnectionStringException("parse error. token is null. Expected token=')");
        }
        // We can check by == because the token object is singleton.
        if (!(token == TOKEN_KEY_END_OBJECT)) {
            throw new OracleConnectionStringException("Syntax error. Expected token=')' :" + token.getToken());
        }
    }

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Complete each pair so it reads (KEY=value) with the '=' and value present and the block closed with ')'
  2. Re-copy the descriptor from the original source and diff against the failing URL
  3. Check config preprocessing (quoting, escaping, templating) isn't stripping the '=' and remainder
  4. Fail fast in config validation by pre-parsing the JDBC URL at startup

Example fix

// before
String url = "jdbc:oracle:thin:@(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME"; // ends after key
// after
String url = "jdbc:oracle:thin:@(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=svc)))";
Defensive patterns

Strategy: validation

Validate before calling

static boolean hasKeyValuePairs(String descriptor) {
    // naive check: no block ends right after an identifier without '='
    return !descriptor.matches(".*\\([A-Za-z_][A-Za-z0-9_]*$.*")
        && descriptor.endsWith(")");
}

Try / catch

try {
    parser.parse(url);
} catch (OracleConnectionStringException e) {
    log.error("Oracle descriptor ended after a key, missing '=': {}", url, e);
    throw new ConfigurationException("Incomplete KEY=value pair in descriptor", e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/9ae8c8b60d833127. Report an issue: GitHub.