{"record":{"id":"c1f4c3cf7a75357e","repo":"stanfordnlp/CoreNLP","slug":"max-end-is-not-as-expected","errorCode":null,"errorMessage":"max end is not as expected!!!","messagePattern":"max end is not as expected!!!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/util/IntervalTree.java","lineNumber":378,"sourceCode":"      }\n      if (node.isEmpty()) {\n        if (node.left != null) throw new IllegalStateException(\"Empty node shouldn't have left branch\");\n        if (node.right != null) throw new IllegalStateException(\"Empty node shouldn't have right branch\");\n        continue;\n      }\n      int leftSize = (node.left != null)? node.left.size:0;\n      int rightSize = (node.right != null)? node.right.size:0;\n      E leftMax = (node.left != null)? node.left.maxEnd:null;\n      E rightMax = (node.right != null)? node.right.maxEnd:null;\n      E maxEnd = node.value.getInterval().getEnd();\n      if (leftMax != null && leftMax.compareTo(maxEnd) > 0) {\n        maxEnd = leftMax;\n      }\n      if (rightMax != null && rightMax.compareTo(maxEnd) > 0) {\n        maxEnd = rightMax;\n      }\n      if (!maxEnd.equals(node.maxEnd)) {\n        throw new IllegalStateException(\"max end is not as expected!!!\");\n      }\n      if (node.size != leftSize + rightSize + 1) {\n        throw new IllegalStateException(\"node size is not one plus the sum of left and right!!!\");\n      }\n      if (node.left != null) {\n        if (node.left.parent != node) {\n          throw new IllegalStateException(\"node left parent is not same as node!!!\");\n        }\n      }\n      if (node.right != null) {\n        if (node.right.parent != node) {\n          throw new IllegalStateException(\"node right parent is not same as node!!!\");\n        }\n      }\n      if (node.parent != null) {\n        // Go up parent and make sure we are on correct side\n        TreeNode<E,T> n = node;\n        while (n != null && n.parent != null) {","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/util/IntervalTree.java#L360-L396","documentation":"Each TreeNode caches maxEnd = the maximum interval endpoint in its subtree so overlap queries work. check() recomputes maxEnd from the node's own value and its children's cached values and throws this IllegalStateException when the stored maxEnd differs. It means an augment value was not recomputed after insert/remove/rotation — i.e. the tree's internal bookkeeping is stale or corrupted.","triggerScenarios":"check() (or balance()/rotateUp() that invoke it) finds recomputed maxEnd (max of node value's endpoint, leftMax, rightMax) not equal to node.maxEnd — after an operation that changed the subtree without updating maxEnd.","commonSituations":"Seen when debugging custom interval types whose compareTo/endpoint semantics are inconsistent; when mutation of an Interval object after insertion changes its endpoint without updating the tree; after rotation bugs in CoreNLP's IntervalTree.","solutions":["Never mutate an Interval (or its endpoints) after inserting it into the tree; remove and re-insert with the new value instead.","Ensure the interval type's getInterval()/compareTo implement a consistent endpoint ordering so maxEnd recomputation matches caching.","Rebuild the tree to restore consistent maxEnd values if corruption already occurred.","Reproduce minimal failing insert/remove sequence and report to Stanford CoreNLP if triggered purely by public API."],"exampleFix":"// before\ninterval.setEnd(newEnd); // mutates a stored interval, maxEnd now stale\n// after\ntree.remove(interval, value);\nInterval<E> updated = new Interval<>(interval.getStart(), newEnd);\ntree.insert(updated, value);","handlingStrategy":"validation","validationCode":"// Guard: never insert an interval you plan to mutate later\nboolean safeToInsert(Interval<E> iv) {\n  return iv != null && iv.getInterval() != null && isEffectivelyImmutable(iv);\n}","typeGuard":null,"tryCatchPattern":"try {\n  tree.check(tree.root);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"max end\")) { tree = rebuildTree(intervals); }\n}","preventionTips":["Treat inserted intervals as immutable: create a new Interval instead of changing endpoints in place.","Implement compareTo on your interval type consistently (start then end).","Run check() after insert bursts in unit tests to catch stale maxEnd early.","Keep source interval data to enable full rebuild on corruption."],"tags":["interval-tree","invariant","augmented-tree","corenlp"],"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-17T15:17:12.973Z"}