languagetool-org/languagetool · error · RuntimeException

Could not map ${plainTextPosition} to original position. isT

Error message

Could not map ${plainTextPosition} to original position. isToPos: ${isToPos}, ${msg}

What it means

After searching the markup-mapping for the entry closest to the requested plain-text position, getOriginalTextPositionFor() throws if no mapping entry matched at all (bestMatch == null). This means the internal mapping between plain text and original markup is empty or inconsistent with the requested position, so no original position can be produced.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/markup/AnnotatedText.java:131

    if (mapping.isEmpty()) {
      return 0;
    }
    int minDiff = Integer.MAX_VALUE;
    MappingValue bestMatch = null;
    // algorithm: find the closest lower position
    for (Map.Entry<Integer, MappingValue> entry : mapping.entrySet()) {
      int maybeClosePosition = entry.getKey();
      if (plainTextPosition < maybeClosePosition) {
        int diff = maybeClosePosition - plainTextPosition;
        if (diff > 0 && diff < minDiff) {
          bestMatch = entry.getValue();
          minDiff = diff;
        }
      }
    }
    if (bestMatch == null) {
      String msg = "mappings: " + (mapping.size() < 5 ? mapping : mapping.size());
      throw new RuntimeException("Could not map " + plainTextPosition + " to original position. isToPos: " + isToPos + ", " + msg);
    }
    // we remove markup total length if usage of fake markup and need from position
    if (!isToPos && bestMatch.getFakeMarkupLength() > 0) {
      minDiff = bestMatch.getFakeMarkupLength();
    }
    // We assume that when we have found the closest match there's a one-to-one mapping
    // in this region, thus we can subtract 'minDiff' to get the exact position.
    // If the bestMatch is a fakeMarkup, subtract it:
    return bestMatch.getTotalPosition() - minDiff;
  }
  
  /**
   * @since 3.9
   */
  public String getGlobalMetaData(String key, String defaultValue) {
    return customMetaData.getOrDefault(key, defaultValue);
  }

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Ensure rule-match offsets come from the same AnnotatedText/AnnotatedTextBuilder instance that is being checked.
  2. Verify the text was built via AnnotatedTextBuilder (addMarkup/addText) so the mapping is populated consistently.
  3. Guard against mapping/empty or out-of-range positions before calling the API.
  4. If it comes from a plugin/integration, upgrade LanguageTool — mapping logic changed across versions.

Example fix

// before
int orig = annotatedText.getOriginalTextPositionFor(ruleMatch.getFromPos(), false);
// after: build and use the same text instance for matching and mapping
AnnotatedText at = new AnnotatedTextBuilder().addText("...").build();
List<RuleMatch> ms = langTool.check(at);
int orig = at.getOriginalTextPositionFor(ms.get(0).getFromPos(), false);
Defensive patterns

Strategy: try-catch

Try / catch

try {
  int orig = text.getOriginalTextPositionFor(pos, false);
} catch (RuntimeException e) {
  if (e.getMessage().startsWith("Could not map")) {
    log.warn("Offset mapping failed; check text/mapping consistency", e);
  }
}

Prevention

When it happens

Trigger: Calling getOriginalTextPositionFor() on an AnnotatedText whose mapping produced no best match for plainTextPosition — e.g. the mapping is empty but not caught earlier, or position lies outside the mapped region and closest-match logic fails; thrown with isToPos and a debug dump of mappings (contents if <5 entries, else size).

Common situations: Rule match offsets computed against a different text object than the one being mapped (mismatched plain text vs markup); bugs in AnnotatedTextBuilder usage where text was added without matching markup entries.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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