stanfordnlp/CoreNLP · error · RuntimeException

Tree is not properly binary

Error message

Tree <treeNum> is not properly binary

What it means

OutputSubtrees extracts subtrees from a treebank and, when ASSERT_BINARY is enabled (set via -assertBinary), requires every input tree to be strictly binary (each internal node has exactly two children). This guard throws a RuntimeException identifying the 1-based tree number of the first non-binary tree.

Solutions

  1. Binarize the trees before processing, e.g. with TreeBinarizer (boundaryGenerator) or by running the trees through a parser that binarizes.
  2. Remove the -assertBinary flag if strict binary structure is not actually required, letting n-ary subtrees pass through.
  3. Locate the offending tree (message gives the 1-based number) and inspect/repair its structure.
  4. Ensure consistent preprocessing across all treebank files in the input path.

Example fix

// before
for (Tree t : treebank) { outputSubtrees(t); }
// after
TreeBinarizer bin = TreeBinarizer.boundaryFactories? -> use:
TreeBinarizer bin = TreeBinarizer.buildSimpleBinarizer("HEAD", "-TMP", false, false, false, op, false, 1.0, 0, tlpp.getBasicCategoryFunction(), false);
for (Tree t : treebank) { outputSubtrees(bin.transformTree(t)); }
Defensive patterns

Strategy: validation

Validate before calling

// Verify binary-ness before running OutputSubtrees
treebank.forEach(t -> {
  for (Tree n : t) {
    if (!n.isLeaf() && n.numChildren() != 2)
      throw new IllegalArgumentException("Non-binary node found: " + n.value());
  }
});

Try / catch

try {
  OutputSubtrees.main(args);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().endsWith("is not properly binary")) {
    log.error(e.getMessage() + " — binarize input with TreeBinarizer first");
  } else throw e;
}

Prevention

When it happens

Trigger: Running OutputSubtrees.main with -assertBinary=true on a treebank containing flat/n-ary constituents (e.g. raw Penn Treebank trees with 3+ children under a node, or unary chains mishandled), typically when the trees were not passed through TreeBinarizer first.

Common situations: Feeding the original Penn Treebank (unbinarized) trees directly; using the wrong binarization options for the downstream model; concatenating treebanks where some files were binarized and others not.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/cd20226292cd049c. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/trees/OutputSubtrees.java:92

    } else {
      remap = Collections.emptyMap();
    }

    MemoryTreebank treebank = new MemoryTreebank("utf-8");
    treebank.loadPath(INPUT, null);

    final Writer output;
    if (OUTPUT == null) {
      output = IOUtils.encodedOutputStreamWriter(System.out, "utf-8");
    } else {
      output = IOUtils.getPrintWriter(OUTPUT, "utf-8");
    }

    int treeNum = 0;
    for (Tree tree : treebank) {
      ++treeNum;
      if (ASSERT_BINARY && !tree.isBinary()) {
        throw new RuntimeException("Tree " + treeNum + " is not properly binary");
      }
      //System.out.println(tree);
      //System.out.println("--------------");
      Iterable<Tree> subtrees = (ROOT_ONLY) ? Collections.singletonList(tree) : tree;
      for (Tree subtree : subtrees) {
        if (subtree.isLeaf()) {
          continue;
        }
        String value = subtree.label().value();
        List<Tree> leaves = Trees.leaves(subtree);
        List<Label> labels = leaves.stream().map(x -> x.label()).collect(Collectors.toList());
        String text = SentenceUtils.listToString(labels);
        if (ignored.contains(value)) {
          continue;
        }
        if (remap.containsKey(value)) {
          value = remap.get(value);
        }

View on GitHub (pinned to 1b7edd19c4)