{"record":{"id":"29e4d10c5a4114fb","repo":"stanfordnlp/CoreNLP","slug":"expected-corelabel-s-to-have-after-text","errorCode":null,"errorMessage":"Expected CoreLabel's to have after() text","messagePattern":"Expected CoreLabel's to have after\\(\\) text","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/Tree.java","lineNumber":1023,"sourceCode":"    return sw.toString();\n  }\n\n  /**\n   * Return String of leaves spanned by this tree assuming they are CoreLabel's\n   * Throws an IllegalArgumentException if the leaves are not CoreLabels that contain\n   * text info as in the typical use case of a Tree generated by a pipeline\n   *\n   * @return The text of the span of this Tree\n   */\n  public String spanString() {\n    // check this Tree supports this method by having properly populated CoreLabel's\n    List<Tree> leaves = this.getLeaves();\n    if (!(leaves.get(0).label() instanceof CoreLabel)) {\n      throw new IllegalArgumentException(\"Expected leaves to be CoreLabels\");\n    } else if (((CoreLabel) leaves.get(0).label()).word() == null) {\n      throw new IllegalArgumentException(\"Expected CoreLabel's to have text\");\n    } else if (((CoreLabel) leaves.get(0).label()).after() == null) {\n      throw new IllegalArgumentException(\"Expected CoreLabel's to have after() text\");\n    }\n    List<CoreLabel> coreLabels = this.getLeaves().stream().map(l -> ((CoreLabel) l.label())).collect(Collectors.toList());\n    // reconstruct original String from CoreLabel fields\n    String spanString = coreLabels.subList(0, Math.max(0, coreLabels.size()-1)).stream().map(\n            cl -> cl.word()+cl.after()).collect(Collectors.joining(\"\"));\n    // don't add the after of the last word\n    spanString += coreLabels.get(coreLabels.size()-1).word();\n    return spanString;\n  }\n\n\n  /**\n   * Print the tree as done in Penn Treebank merged files.\n   * The formatting should be exactly the same, but we don't print the\n   * trailing whitespace found in Penn Treebank trees.\n   * The tree is printed to {@code System.out}. The basic deviation\n   * from a bracketed indented tree is to in general\n   * collapse the printing of adjacent preterminals onto one line of","sourceCodeStart":1005,"sourceCodeEnd":1041,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/Tree.java#L1005-L1041","documentation":"To reproduce original spacing, spanString() reads CoreLabel.after() (the whitespace/characters following each word, BeforeAnnotation). If after() is null the reconstruction is ambiguous, so the library throws IllegalArgumentException for the first leaf lacking it.","triggerScenarios":"Calling spanString() on a tree whose leaf CoreLabels have word() set but never had the AfterAnnotation populated (e.g. labels built manually without whitespace info, or tokenizers that do not record trailing whitespace).","commonSituations":"Manually constructed CoreLabels in tests/pipelines where only word and tag were set; importing trees from other toolkits that don't track after-text; running spanString() on trees not produced by CoreNLP tokenization.","solutions":["Populate after() on each leaf, e.g. ((CoreLabel) leaf.label()).setAfter(\" \") (or the actual trailing text) before spanString()","Use CoreNLP's tokenizer (PTBTokenizer) which sets AfterAnnotation automatically, then build trees from its tokens","Wrap spanString() in a null/after check and fall back to joining words with single spaces"],"exampleFix":"// before\nString s = tree.spanString(); // throws when after()==null\n// after\nfor (Tree leaf : tree.getLeaves()) { CoreLabel cl = (CoreLabel) leaf.label(); if (cl.after() == null) cl.setAfter(\" \"); }\nString s = tree.spanString();","handlingStrategy":"validation","validationCode":"for (Tree leaf : tree.getLeaves()) { CoreLabel cl = (CoreLabel) leaf.label(); if (cl.after() == null) cl.setAfter(\" \"); }","typeGuard":"boolean leavesHaveAfter(Tree t) { return t.getLeaves().stream().allMatch(l -> ((CoreLabel) l.label()).after() != null); }","tryCatchPattern":"try { return tree.spanString(); } catch (IllegalArgumentException e) { fillMissingAfter(tree); return tree.spanString(); }","preventionTips":["Prefer PTBTokenizer-produced tokens that carry AfterAnnotation","Default after() to a single space when building labels manually","Check after() before calling surface-text reconstruction"],"tags":["validation","nlp","corelabel"],"backgroundTag":"empty-required-field","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"}