languagetool-org/languagetool · error · RuntimeException

No 'data' found in grammalecte JSON: " + map

Error message

No 'data' found in grammalecte JSON: " + map

What it means

GrammalecteRule.parseJson deserializes the Grammalecte server's response and requires a top-level 'data' array holding the rule matches. When the key is absent (matches == null), it throws this RuntimeException; the surrounding match() is expected to handle it, since a response without 'data' means the server replied in an unexpected shape (often an error page or a different API version).

Source

Thrown at languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/GrammalecteRule.java:653

      List<RuleMatch> ruleMatches = parseJson(input);
      return toRuleMatchArray(ruleMatches);
    } catch (Exception e) {
      lastRequestError = System.currentTimeMillis();
      // These are issue that can be request-specific, like wrong parameters. We don't throw an
      // exception, as the calling code would otherwise assume this is a persistent error:
      logger.warn("Warn: Failed to query Grammalecte server at " + serverUrl, e);
    } finally {
      huc.disconnect();
    }
    return RuleMatch.EMPTY_ARRAY;
  }

  @NotNull
  private List<RuleMatch> parseJson(InputStream inputStream) throws IOException {
    Map map = mapper.readValue(inputStream, Map.class);
    List matches = (ArrayList) map.get("data");
    if (matches == null) {
      throw new RuntimeException("No 'data' found in grammalecte JSON: " + map);  // handled in match()
    }
    List<RuleMatch> result = new ArrayList<>();
    for (Object match : matches) {
      List<RuleMatch> remoteMatches = getMatches((Map<String, Object>)match);
      result.addAll(remoteMatches);
    }
    return result;
  }

  protected String encode(String plainText) throws UnsupportedEncodingException {
    return URLEncoder.encode(plainText, StandardCharsets.UTF_8.name());
  }

  @NotNull
  private List<RuleMatch> getMatches(Map<String, Object> match) {
    List<RuleMatch> remoteMatches = new ArrayList<>();
    ArrayList matches = (ArrayList) match.get("lGrammarErrors");
    for (Object o : matches) {

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Check that the configured Grammalecte server URL is correct and reachable (curl it and inspect the raw JSON).
  2. Upgrade/downgrade the Grammalecte server to a version whose response contains the 'data' array.
  3. Ensure no proxy or error page is intercepting the request; verify response content-type is application/json from Grammalecte.
  4. The comment says it's handled in match() — confirm your caller catches this and reports a degraded result instead of failing the session.
Defensive patterns

Strategy: try-catch

Validate before calling

// before trusting the response
Map map = mapper.readValue(inputStream, Map.class);
if (map == null || !map.containsKey("data")) {
    LOG.warn("Grammalecte response missing 'data': " + map);
    return Collections.emptyList();
}

Try / catch

try { matches = rule.ruleMatches(text, sentence); } catch (RuntimeException e) { LOG.warn("Grammalecte unavailable: " + e.getMessage()); matches = Collections.emptyList(); }

Prevention

When it happens

Trigger: ruleMatches calls parseJson with an InputStream whose parsed JSON map has no 'data' entry — e.g. the Grammalecte server returned an error payload, a non-grammalecte response (proxy/captive portal), or an incompatible Grammalecte version with a changed response schema.

Common situations: Grammalecte server down and something upstream answers with an HTML error page that happens to parse as JSON, wrong grammalecte server URL/port configured, version mismatch between LanguageTool and the Grammalecte server API.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/6453b2c0a2458d52. Report an issue: GitHub.