{"record":{"id":"1b946b397940fe9c","repo":"stanfordnlp/CoreNLP","slug":"tree-added-a-child-before-a-label-was-added-to-a-n","errorCode":null,"errorMessage":"Tree added a child before a label was added to a node!  Offending proto: ${proto}","messagePattern":"Tree added a child before a label was added to a node!  Offending proto: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/pipeline/ProtobufAnnotationSerializer.java","lineNumber":2216,"sourceCode":"    if (proto.getNodesList().size() == 0) {\n      return null;\n    }\n    Stack<LabeledScoredTreeNode> stack = new Stack<>();\n    LabeledScoredTreeNode finished = null;\n\n    // The incoming data structure is basically a PTB formatted tree\n    // with openNode representing ( and closeNode representing )\n    // essentially we only need to keep track of the current node and\n    // all of its ancestors\n    // we do that in a stack.  as we finish a node, we add it to the\n    // appropriate parent and forget about it\n    for (CoreNLPProtos.FlattenedParseTree.Node next : proto.getNodesList()) {\n      if (finished != null) {\n        throw new IllegalArgumentException(\"Tree continued after it was already closed!  Offending proto: \" + proto);\n      }\n      if (next.hasOpenNode()) {\n        if (stack.size() > 0 && stack.peek().label() == null) {\n          throw new IllegalArgumentException(\"Tree added a child before a label was added to a node!  Offending proto: \" + proto);\n        }\n        LabeledScoredTreeNode newNode = new LabeledScoredTreeNode();\n        stack.push(newNode);\n        if (next.hasScore()) {\n          newNode.setScore(next.getScore());\n        }\n      } else if (next.hasCloseNode()) {\n        if (stack.size() == 0) {\n          // demand that the tree always start with an Open\n          throw new IllegalArgumentException(\"Tree started with a Close, not an Open!  Offending proto: \" + proto);\n        }\n        LabeledScoredTreeNode child = stack.pop();\n        if (stack.size() == 0) {\n          // Popped off the last node.  Guess we're done.\n          // We don't return yet so that we check that the\n          // iterator is finished first\n          finished = child;\n        } else {","sourceCodeStart":2198,"sourceCodeEnd":2234,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/pipeline/ProtobufAnnotationSerializer.java#L2198-L2234","documentation":"During fromProtoFlattenedTree reconstruction, an Open node marker may not be pushed onto the stack while the node on top of the stack still has no label — the flattened format requires label-before-children. Violating this ordering yields an IllegalArgumentException identifying the offending proto.","triggerScenarios":"Deserializing a FlattenedParseTree proto where an OpenNode entry appears before a label/value entry for the currently open parent node, e.g. a hand-built proto with nodes ordered Open, Open, label instead of Open, label, Open.","commonSituations":"Custom code constructing FlattenedParseTree protos directly instead of using toFlattenedTree; language-specific writers that emit children before the node label.","solutions":["Build flattened trees with ProtobufAnnotationSerializer.toFlattenedTree so ordering is guaranteed.","Reorder nodes so each Open node is immediately followed by its label node before any child Open.","Catch IllegalArgumentException and log/replace the malformed parse annotation."],"exampleFix":"// before (wrong order)\nb.addNodes(open(parent)); b.addNodes(open(child)); b.addNodes(label(parent));\n// after\nb.addNodes(open(parent)); b.addNodes(label(parent)); b.addNodes(open(child));","handlingStrategy":"validation","validationCode":"// every Open at depth>=1 must be preceded by a label for the parent\nfor (int i = 1; i < proto.getNodesCount(); i++) {\n  var prev = proto.getNodes(i - 1);\n  var cur = proto.getNodes(i);\n  if (cur.hasOpenNode() && prev.hasOpenNode()) {\n    throw new IllegalArgumentException(\"Open followed by Open without label at \" + i);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  tree = ProtobufAnnotationSerializer.fromProto(proto);\n} catch (IllegalArgumentException e) {\n  log.warn(\"Bad node ordering in flattened tree: \" + e.getMessage());\n  tree = null;\n}","preventionTips":["Emit label immediately after each Open node before children","Use toFlattenedTree instead of hand-building node lists","Add a round-trip unit test: toFlattenedTree -> fromProto"],"tags":["serialization","protobuf","tree","malformed-input"],"backgroundTag":"protobuf-unmarshal-failed","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"}