{"record":{"id":"0b7bdbc58031d18f","repo":"stanfordnlp/CoreNLP","slug":"no-named-tregex-nodes-allowed-in-the-scope-of-nega-0b7bdb","errorCode":null,"errorMessage":"No named tregex nodes allowed in the scope of negation.","messagePattern":"No named tregex nodes allowed in the scope of negation\\.","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/tregex/TregexParser.jj","lineNumber":169,"sourceCode":"  boolean link = false;\n  Token groupNum;\n  Token groupVar;\n  List<Pair<Integer,String>> varGroups = new ArrayList<Pair<Integer,String>>();\n} {\n// this is how we match tokens\n// the return value of tokens is a Token object\n  ( ( ( desc = <IDENTIFIER> | desc = <REGEX> | desc = <BLANK> | desc = <ROOTNODE> )\n    ( ( \"#\" groupNum = <NUMBER> \"%\" groupVar = <IDENTIFIER> ) {\n        varGroups.add(new Pair<Integer,String>(Integer.parseInt(groupNum.image),groupVar.image));\n      } )*\n      ( ( \"=\" name = <IDENTIFIER> )\n        { if (knownVariables.contains(name.image)) {\n            throw new ParseException(\"Variable \" + name.image + \" has been declared twice, which makes no sense\");\n          } else {\n            knownVariables.add(name.image);\n          }\n          if (underNegation)\n            throw new ParseException(\"No named tregex nodes allowed in the scope of negation.\");\n        } )? ) |\n    ( ( \"~\" linkedName = <IDENTIFIER> ) ( \"=\" name = <IDENTIFIER> )? {\n        if (!knownVariables.contains(linkedName.image)) {\n          throw new ParseException(\"Variable \" + linkedName.image +\n                                   \" was referenced before it was declared\");\n        }\n        if (name != null) {\n          if (knownVariables.contains(name.image)) {\n            throw new ParseException(\"Variable \" + name.image + \" has been declared twice, which makes no sense\");\n          } else {\n            knownVariables.add(name.image);\n          }\n        }\n        link = true;\n      } ) |\n    ( ( \"=\" ) name = <IDENTIFIER> {\n        if (!knownVariables.contains(name.image)) {\n          throw new ParseException(\"Variable \" + name.image +","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/tregex/TregexParser.jj#L151-L187","documentation":"TregexParseException: tregex allows naming nodes with \"=name\" so matches can be captured, but names are not permitted inside the scope of a negation (\"!\"). The parser tracks an underNegation flag while parsing and rejects any named node encountered there, because capturing from a negated (absent) subtree is semantically meaningless.","triggerScenarios":"Compiling a pattern like \"A !<< (B << C=name)\" where a \"=name\" label appears inside a negated subexpression; the check `if (underNegation)` at TregexParser.jj:169 fires on the name declaration inside the negation scope.","commonSituations":"Writing patterns like \"no child matches X\" and additionally trying to capture a node inside that negative context; translating regex-like intuition ('capture what did NOT match') into tregex.","solutions":["Move the \"=name\" label out of the negated subtree onto a node outside the negation.","Split the pattern: match positively with the label, then filter results in code, or use a separate negated conjunction.","If the name is unused (only for grouping), drop it entirely."],"exampleFix":"// before\nTregexPattern p = TregexPattern.compile(\"NP !<< (S << VP=verb)\");\n// after\nTregexPattern p = TregexPattern.compile(\"NP !<< S\"); // capture outside negation instead","handlingStrategy":"validation","validationCode":"boolean hasNameInsideNegation(String pattern) {\n  int depth = 0; boolean inNeg = false;\n  for (int i = 0; i < pattern.length(); i++) {\n    char c = pattern.charAt(i);\n    if (c == '!') inNeg = true;\n    if (c == '(' && inNeg) depth++;\n    if (c == ')' && inNeg && depth > 0 && --depth == 0) inNeg = false;\n    if (c == '=' && inNeg) return true;\n  }\n  return false;\n}","typeGuard":null,"tryCatchPattern":"try { return TregexPattern.compile(pattern); } catch (TregexParseException e) { throw new IllegalArgumentException(\"Names are not allowed under negation: \" + pattern, e); }","preventionTips":["Never put \"=name\" inside a \"!\" scope","Capture on the positive side of the pattern and filter in code","Document pattern-authoring rules for your team"],"tags":["parser","tregex","negation"],"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"}