languagetool-org/languagetool · error · RuntimeException

plainTextPosition must be > 0 - its value starts at 1

Error message

plainTextPosition must be > 0 - its value starts at 1

What it means

PlainTextMapping maps positions in converted plain text back to original Wikipedia text positions. Positions are one-based, so getOriginalTextPositionFor rejects values below 1 with this RuntimeException. It indicates a caller passed a zero-based or invalid position.

Source

Thrown at languagetool-wikipedia/src/main/java/org/languagetool/dev/wikipedia/PlainTextMapping.java:52

  public PlainTextMapping(String plainText, Map<Integer, Location> mapping) {
    this.plainText = plainText;
    this.mapping = mapping;
  }

  public String getPlainText() {
    return plainText;
  }

  public Map<Integer, Location> getMapping() {
    return mapping;
  }

  /**
   * @param plainTextPosition not zero-based - smallest value is 1!
   */
  public Location getOriginalTextPositionFor(int plainTextPosition) {
    if (plainTextPosition < 1) {
      throw new RuntimeException("plainTextPosition must be > 0 - its value starts at 1");
    }
    Location origPosition = mapping.get(plainTextPosition);
    if (origPosition != null) {
      //System.out.println("mapping " + plainTextPosition + " to " + origPosition + " [direct]");
      return origPosition;
    }
    int minDiff = Integer.MAX_VALUE;
    Location bestMatch = null;
    //Integer bestMaybeClosePosition = null;
    // algorithm: find the closest lower position
    for (Map.Entry<Integer, Location> entry : mapping.entrySet()) {
      int maybeClosePosition = entry.getKey();
      if (plainTextPosition > maybeClosePosition) {
        int diff = plainTextPosition - maybeClosePosition;
        if (diff >= 0 && diff < minDiff) {
          bestMatch = entry.getValue();
          //bestMaybeClosePosition = maybeClosePosition;
          minDiff = diff;

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Pass 1-based positions: add 1 to zero-based offsets before calling
  2. Clamp/validate positions before the call
  3. Check loop bounds so the position never drops below 1

Example fix

// before
Location loc = mapping.getOriginalTextPositionFor(idx);
// after
Location loc = mapping.getOriginalTextPositionFor(idx + 1); // positions are 1-based
Defensive patterns

Strategy: validation

Validate before calling

if (pos < 1) throw new IllegalArgumentException("plainTextPosition is 1-based, got " + pos);

Type guard

boolean isValidPosition(Integer p) { return p != null && p >= 1; }

Try / catch

try {
  loc = mapping.getOriginalTextPositionFor(pos);
} catch (RuntimeException e) {
  loc = mapping.getOriginalTextPositionFor(Math.max(1, pos));
}

Prevention

When it happens

Trigger: Calling getOriginalTextPositionFor(0) or with a negative value — typically passing a zero-based offset/char index into this one-based API.

Common situations: Off-by-one errors when tracking text positions in downstream tools; iterating arrays with 0-based indices and feeding them directly to the mapping.

Related errors


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