elastic/elasticsearch · error · IllegalArgumentException

CompilationUnit has no lexical information for output

Error message

CompilationUnit has no lexical information for output

What it means

Thrown by AbstractVersionsTask.writeOutNewContents when the JavaParser CompilationUnit does not carry the LexicalPreservingPrinter.NODE_TEXT_DATA, meaning LexicalPreservingPrinter.setup() was never called on the parsed source. Without lexical info, LexicalPreservingPrinter.print cannot reproduce the original formatting, so the task refuses to write to avoid corrupting the source file.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/AbstractVersionsTask.java:159

    static OptionalInt findSingleIntegerExpr(FieldDeclaration field) {
        var ints = field.findAll(IntegerLiteralExpr.class);
        switch (ints.size()) {
            case 0 -> {
                return OptionalInt.empty();
            }
            case 1 -> {
                return OptionalInt.of(ints.get(0).asNumber().intValue());
            }
            default -> {
                LOGGER.warn("Multiple integers found in version field declaration [{}]", field); // and ignore it
                return OptionalInt.empty();
            }
        }
    }

    static void writeOutNewContents(Path file, CompilationUnit unit) throws IOException {
        if (unit.containsData(LexicalPreservingPrinter.NODE_TEXT_DATA) == false) {
            throw new IllegalArgumentException("CompilationUnit has no lexical information for output");
        }
        Files.writeString(file, LexicalPreservingPrinter.print(unit), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
    }
}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Ensure LexicalPreservingPrinter.setup(unit) is invoked right after parsing the source file and before any modification.
  2. Do not construct a CompilationUnit via 'new CompilationUnit()' for output that must preserve formatting — parse the real file and call setup.
  3. Re-run the release/version-rewrite task to confirm round-trip output is formatted correctly.

Example fix

// before
CompilationUnit unit = StaticJavaParser.parse(file);
// ... mutate unit ...
writeOutNewContents(file, unit); // throws: no lexical info
// after
CompilationUnit unit = StaticJavaParser.parse(file);
LexicalPreservingPrinter.setup(unit);
// ... mutate unit ...
writeOutNewContents(file, unit);
Defensive patterns

Strategy: validation

Validate before calling

CompilationUnit unit = StaticJavaParser.parse(file);
LexicalPreservingPrinter.setup(unit); // MUST precede any mutation
if (unit.containsData(LexicalPreservingPrinter.NODE_TEXT_DATA) == false) {
    throw new IllegalStateException("LexicalPreservingPrinter not set up for " + file);
}

Prevention

When it happens

Trigger: A CompilationUnit is parsed (StaticJavaParser.parse) and modified, then passed to writeOutNewContents. The guard checks unit.containsData(LexicalPreservingPrinter.NODE_TEXT_DATA); if the caller forgot to call LexicalPreservingPrinter.setup(unit) immediately after parsing (before observing/altering the tree), the data key is absent and the throw fires.

Common situations: Adding a new code path that transforms a parsed Java file but omits the LexicalPreservingPrinter.setup call; refactoring an existing release-version-rewriting routine and dropping the setup line; using a fresh CompilationUnit built programmatically rather than parsed+setup for round-trip printing.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/c3bede7fd6c2c438. Report an issue: GitHub.