languagetool-org/languagetool · error
Failed to parse line
Error message
Failed to parse line
What it means
LightRuleMatchParser.parseAggregatedJson wraps any exception raised while parsing a line of the aggregated JSON input file into a RuntimeException. The message includes the line number (lineCount) and the input file path so the offending JSON line can be located; the original exception is attached as the cause (e.g. Jackson mapping or NPE errors).
Source
Thrown at languagetool-dev/src/main/java/org/languagetool/dev/diff/LightRuleMatchParser.java:72
ObjectMapper mapper = new ObjectMapper();
List<LightRuleMatch> ruleMatches = new ArrayList<>();
Set<String> buildDates = new HashSet<>();
int lineCount = 1;
try (Scanner scanner = new Scanner(inputFile)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
JsonNode node = mapper.readTree(line);
JsonNode matches = node.get("matches");
JsonNode software = node.get("software");
String buildDate = software != null ? software.get("buildDate").asText() : "unknown";
buildDates.add(buildDate);
for (JsonNode match : matches) {
ruleMatches.add(nodeToLightMatch(node.get("title").asText(), match));
}
lineCount++;
}
} catch (Exception e) {
throw new RuntimeException("Failed to parse line " + lineCount + " of " + inputFile, e);
}
return new JsonParseResult(ruleMatches, buildDates);
}
@NotNull
private LightRuleMatch nodeToLightMatch(String title, JsonNode match) {
int offset = match.get("offset").asInt();
JsonNode rule = match.get("rule");
String ruleId = rule.get("id").asText();
String fullRuleId = rule.get("subId") != null ? ruleId + "[" + rule.get("subId").asText() + "]" : ruleId;
String message = match.get("message").asText();
String category = rule.get("category") != null ? rule.get("category").get("name").asText() : "(unknown)";
//TODO: Maybe just works for xml rules
boolean isPremium = rule.get("isPremium") != null && rule.get("isPremium").asBoolean(false);
int contextOffset = match.get("context").get("offset").asInt();
int contextLength = match.get("context").get("length").asInt();
String context = match.get("context").get("text").asText();
int maxEnd = Math.min(contextOffset + contextLength, context.length());View on GitHub (pinned to 2e990059ce)
Solutions
- Open the input file at the reported line number and fix or remove the malformed JSON line
- Regenerate the aggregated input file with the same LanguageTool version the parser expects
- Validate each line is complete JSON (e.g. with jq) before feeding it to the parser
- Inspect the cause chain (e.getCause()) to see whether it is a JSON syntax error or a missing-field NPE
Example fix
// before: feeding possibly blank/truncated lines
result = parser.parseOutput(new File("agg.jsonl"));
// after: pre-validate lines
for (String line : Files.readAllLines(Path.of("agg.jsonl"))) {
if (line.isBlank()) continue;
new JsonParser().parse(line); // throws early with clear context
}
result = parser.parseOutput(new File("agg.jsonl")); Defensive patterns
Strategy: validation
Validate before calling
// validate each JSONL line before parsing
for (String line : Files.readAllLines(Path.of(inputFile))) {
if (line.isBlank()) throw new IllegalStateException("blank line in " + inputFile);
JsonNode n = new ObjectMapper().readTree(line);
if (!n.has("matches")) throw new IllegalStateException("line missing 'matches': " + line);
} Type guard
static boolean isValidAggLine(String line) {
try { return new ObjectMapper().readTree(line).has("matches"); }
catch (Exception e) { return false; }
} Try / catch
try {
result = parser.parseOutput(inputFile);
} catch (RuntimeException e) {
// message contains 'Failed to parse line N of FILE'
log.error("aggregated JSON invalid: " + e.getMessage(), e.getCause());
throw new IllegalArgumentException("fix input file at reported line", e);
} Prevention
- Keep line-oriented JSON files machine-generated, never hand-edited
- Validate with jq or a schema checker before feeding to the diff tooling
- Pin the same LanguageTool version for producing and parsing diff files
When it happens
Trigger: Calling parseOutput/parseAggregatedJson on an aggregated JSON file where a line is malformed JSON, is missing expected fields (e.g. 'matches', rule match 'title' node), or has an unexpected structure so nodeToLightMatch throws.
Common situations: Feed files produced by an older LanguageTool version no longer matching the expected aggregated JSON schema; hand-edited or truncated diff input files; running the diff tooling against output from a differently configured server.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Got no rule match:
- WrongParameterNumberException
- Could not check text in file <file>
- Could not create LanguageTool instance for language <languag
- Could not activate rules
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/46e79e3b43e15463.
Report an issue: GitHub.