{"record":{"id":"d8a1503cea85754b","repo":"stanfordnlp/CoreNLP","slug":"error-two-foot-nodes-in-subtree-t-tostring","errorCode":null,"errorMessage":"Error -- two foot nodes in subtree\" + t.toString()","messagePattern":"Error -- two foot nodes in subtree\" \\+ t\\.toString\\(\\)","errorType":"exception","errorClass":"TsurgeonParseException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/tregex/tsurgeon/AuxiliaryTree.java","lineNumber":162,"sourceCode":"    return result;\n  }\n\n  private static Tree findFootNodeHelper(Tree t) {\n    Tree foundDtr = null;\n    if (t.isLeaf()) {\n      Matcher m = footNodeLabelPattern.matcher(t.label().value());\n      if (m.matches()) {\n        t.label().setValue(m.group(1));\n        return t;\n      } else {\n        return null;\n      }\n    }\n    for (Tree child : t.children()) {\n      Tree thisFoundDtr = findFootNodeHelper(child);\n      if (thisFoundDtr != null) {\n        if (foundDtr != null) {\n          throw new TsurgeonParseException(\"Error -- two foot nodes in subtree\" + t.toString());\n        } else {\n          foundDtr = thisFoundDtr;\n        }\n      }\n    }\n    Matcher m = escapedFootNodeCharacter.matcher(t.label().value());\n    t.label().setValue(m.replaceAll(footNodeCharacter));\n    return foundDtr;\n  }\n\n\n  /* ******************************************************* *\n   * below here is init stuff for getting node -> names maps *\n   * ******************************************************* */\n\n  // There are two ways in which you can can match the start of a name\n  // expression.\n  // The first is if you have any number of non-escaping characters","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/tregex/tsurgeon/AuxiliaryTree.java#L144-L180","documentation":"findFootNodeHelper recursively scans an auxiliary tree for the foot node. If more than one node in the subtree carries the foot marker, the scan finds two candidate descendants and throws TsurgeonParseException, because a foot node must be unique.","triggerScenarios":"Constructing an AuxiliaryTree whose tree labels contain the '@' foot escape on two or more nodes, e.g. '{@NP {@PP ...}}'; findFootNode calls this helper and the second found node triggers the throw.","commonSituations":"Hand-written Tsurgeon auxiliary trees where '@' was accidentally duplicated (e.g. applied to both a category label and a value, or copy-pasted to nested nodes); automated generation of aux trees marking every node.","solutions":["Ensure exactly one node label in the auxiliary tree contains the '@' foot marker.","Scan the aux tree string for occurrences of '@' and remove all but the intended attachment-point marker.","Note '@' is also an escape character in labels; if a literal '@' is needed in a label, escape it (see escapedFootNodeCharacter handling) so it is not counted as a foot."],"exampleFix":"// before\nString aux = \"{@SBAR {@NP the dog}}\"; // two foot markers\n// after\nString aux = \"{@SBAR {NP the dog}}\"; // exactly one foot node","handlingStrategy":"validation","validationCode":"int countFootMarkers(String auxTreeString) {\n  int count = 0;\n  for (char c : auxTreeString.toCharArray()) if (c == '@') count++;\n  return count; // must be exactly 1 for a valid auxiliary tree\n}","typeGuard":null,"tryCatchPattern":"try {\n  AuxiliaryTree aux = new AuxiliaryTree(tree, true);\n} catch (TsurgeonParseException e) {\n  if (e.getMessage().contains(\"two foot nodes\")) throw new IllegalArgumentException(\"Aux tree has multiple '@' markers: \" + tree);\n  throw e;\n}","preventionTips":["Audit aux tree strings for duplicate '@' characters before running Tsurgeon.","Escape literal '@' intended as label content so it is not read as a foot marker.","Write unit tests that construct each auxiliary tree used in production scripts."],"tags":["tsurgeon","tree-manipulation","invalid-argument"],"backgroundTag":"invalid-argument-value","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"}