{"record":{"id":"435c4cd996a5995d","repo":"stanfordnlp/CoreNLP","slug":"suffix-pointer-moved-too-far","errorCode":null,"errorMessage":"Suffix pointer moved too far!","messagePattern":"Suffix pointer moved too far!","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/international/arabic/process/IOBUtils.java","lineNumber":660,"sourceCode":"        if (arPrefixSet.contains(segments.get(potentialPrefix)))\n          potentialPrefix++;\n        else\n          nonPrefix = potentialPrefix;\n      }\n      if (potentialSuffix < potentialPrefix || (nonSuffix != NOT_FOUND && nonPrefix != NOT_FOUND))\n        break;\n    }\n    \n    /* Once we have exhausted all known prefixes and suffixes, take the longest\n     * segment that remains to be the head. Break length ties by picking the first one.\n     * \n     * Note that in some cases, no segments will remain (e.g. b# +y), so a\n     * segmented word may have zero or one heads, but never more than one.\n     */\n    if (potentialSuffix < potentialPrefix) {\n      // no head--start and end are index of first suffix\n      if (potentialSuffix + 1 != potentialPrefix)\n        throw new RuntimeException(\"Suffix pointer moved too far!\");\n      return Pair.makePair(potentialSuffix + 1, potentialSuffix + 1);\n    } else {\n      int headIndex = nonPrefix;\n      for (int i = nonPrefix + 1; i <= nonSuffix; i++) {\n        if (segments.get(i).length() > segments.get(headIndex).length())\n          headIndex = i;\n      }\n      return Pair.makePair(headIndex, headIndex + 1);\n    }\n  }\n\n  private static boolean addPrefixMarker(int focus, List<CoreLabel> labeledSequence) {\n    return labeledSequence.get(focus).get(PrefixMarkerAnnotation.class).booleanValue();\n  }\n\n  private static boolean addSuffixMarker(int focus, List<CoreLabel> labeledSequence) {\n    return labeledSequence.get(focus).get(SuffixMarkerAnnotation.class).booleanValue();\n  }","sourceCodeStart":642,"sourceCodeEnd":678,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/international/arabic/process/IOBUtils.java#L642-L678","documentation":"getHeadBounds locates the head (non-prefix, non-suffix core) of a segmented Arabic word. When the computed potentialSuffix pointer lands before potentialPrefix, the code expects them to be exactly one position apart (the degenerate no-head case); otherwise it throws RuntimeException('Suffix pointer moved too far!'), signaling an internal invariant violation in the prefix/suffix stripping logic.","triggerScenarios":"Calling headBounds/getHeadBounds on a token whose computed prefix/suffix pointers are inconsistent — e.g. morphological analysis produced overlapping prefix/suffix segments so the suffix index skipped past the prefix boundary by more than one.","commonSituations":"Corrupted or non-conforming segmentation output fed to the head-extraction utility; a bug or unsupported morphology case where the prefix/suffix tables (e.g. attached al-/w-/b- combinations) make pointers collide.","solutions":["Log/inspect the offending token's segment list to see why potentialSuffix and potentialPrefix diverge","Validate segmentation output (prefix/suffix segments contiguous) before calling getHeadBounds","Fix or update the prefix/suffix stripping rules for the morphology pattern that triggers the collision","Report/patch the invariant violation in IOBUtils if it is a genuine library bug"],"exampleFix":"// before\nPair<Integer,Integer> p = IOBUtils.getHeadBounds(segments, ...); // throws on bad input\n// after\nif (potentialSuffix < potentialPrefix && potentialSuffix + 1 != potentialPrefix) {\n  // sanitize: collapse to empty head instead of throwing\n  return Pair.makePair(potentialPrefix, potentialPrefix);\n}","handlingStrategy":"validation","validationCode":"// ensure prefix/suffix segments do not overlap before head extraction\nif (potentialSuffix < potentialPrefix && potentialSuffix + 1 != potentialPrefix) {\n  throw new IllegalStateException(\"Malformed segmentation for token\");\n}","typeGuard":null,"tryCatchPattern":"try { Pair<Integer,Integer> p = IOBUtils.getHeadBounds(...); } catch (RuntimeException e) { /* log offending token segments */ }","preventionTips":["Log segment lists for tokens that trigger the error and compare against known morphology patterns","Validate segmentation output contiguity before head extraction","Patch prefix/suffix stripping rules for unsupported clitic combinations"],"tags":["java","nlp","invariant","arabic-morphology"],"backgroundTag":"internal-invariant-violation","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}