Skip to content

2.89.0: spurious 'unclosed string literal' errors when file contains long strings (>~97 chars) in chained method calls #1680

Description

@RomanVlasenko

Bug description

When a Java file contains string literals of ~97+ characters inside a chained method call (e.g. .execute("very long SQL...")), the formatter's parser corrupts its internal state and reports spurious unclosed string literal errors in subsequent methods of the same file — even on syntactically valid code. The error always points to column 30 of lines in the next method, making the root cause non-obvious.

Version

palantir-java-format 2.89.0

Minimal reproducer

Save the following as Repro.java and run palantir-java-format --palantir Repro.java:

class Repro {
    void test() throws Exception {
        try (var con = getConnection()) {
            con.createStatement()
                    .execute("ALTER DATABASE tempdb MODIFY FILE (NAME = 'tempdev', FILENAME = 'D:\\tempDb\\DATA\\tempdb.mdf')");
            con.createStatement()
                    .execute("ALTER DATABASE tempdb MODIFY FILE (NAME = 'templog', FILENAME = 'D:\\tempDb\\DATA\\templog.ldf')");
            con.createStatement()
                    .execute("ALTER DATABASE tempdb MODIFY FILE (NAME = 'temp2', FILENAME = 'D:\\tempDb\\DATA\\tempdb_mssql_2.ndf')");
        }
    }

    void anotherMethod() {
        System.out.println("This method is valid but the formatter reports errors here");
    }

    java.sql.Connection getConnection() throws Exception { return null; }
}

Actual output

Repro.java:14:30: error: unclosed string literal
Repro.java:18:30: error: unclosed string literal
Repro.java:22:30: error: unclosed string literal

Lines 14, 18, 22 correspond to anotherMethod() and the getConnection() method — not to the lines with the long strings. The errors reference column 30, which has no relationship to the actual string content.

Expected output

Formatted Java output, exit code 0 — the file is syntactically valid Java.

Workaround

Split the long string literals with concatenation so each part is under ~97 characters:

con.createStatement()
        .execute("ALTER DATABASE tempdb MODIFY FILE"
                + " (NAME = 'tempdev', FILENAME = 'D:\\tempDb\\DATA\\tempdb.mdf')");

Notes

  • The 2.50.0 did not exhibit the bug.
  • The errors point to the wrong lines (subsequent methods, not the offending strings).
  • The threshold appears to be approximately 97 characters of string content when the string is an argument to a chained method call with ~20 characters of preceding indentation.
  • Verified on macOS ARM64, Java 17 (Zulu 17.64.17).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions