{"record":{"id":"3bf607fcc4501b31","repo":"stanfordnlp/CoreNLP","slug":"node-cannot-be-both-negated-and-optional","errorCode":null,"errorMessage":"Node cannot be both negated and optional.","messagePattern":"Node cannot be both negated and optional\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/semgraph/semgrex/SemgrexPattern.java","lineNumber":265,"sourceCode":"  private String patternString; // conceptually final, but can't do because of parsing\n\n  protected Env env; //always set with setEnv to make sure that it is also available to child patterns\n\n  // package private constructor\n  SemgrexPattern() {\n  }\n\n  // NodePattern will return its one child, CoordinationPattern will\n  // return the list of children it conjuncts or disjuncts\n  abstract List<SemgrexPattern> getChildren();\n\n  abstract String localString();\n\n  abstract void setChild(SemgrexPattern child);\n\n  void negate() {\n    if (opt) {\n      throw new RuntimeException(\"Node cannot be both negated and optional.\");\n    }\n    neg = true;\n  }\n\n  void makeOptional() {\n    if (neg) {\n      throw new RuntimeException(\"Node cannot be both negated and optional.\");\n    }\n    opt = true;\n  }\n\n  boolean isNegated() {\n    return neg;\n  }\n\n  boolean isOptional() {\n    return opt;\n  }","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/semgraph/semgrex/SemgrexPattern.java#L247-L283","documentation":"SemgrexPattern.negate() throws this RuntimeException when the pattern node is already marked optional (opt == true). A node cannot simultaneously be negated and optional, since 'maybe absent' and 'must be absent' are contradictory match semantics, so the library treats the combination as an invalid state.","triggerScenarios":"Calling negate() on a SemgrexPattern whose 'opt' flag is already set — e.g. the parser's ModRelation path first marks a node optional via '?' and then applies negation ('!'), or programmatic construction calls makeOptional() before negate().","commonSituations":"Writing patterns like '[? !foo]' or equivalent modifier combinations parsed through ModRelation; programmatic pattern building where flags are applied in an order that allows both to be set; template-generated patterns where both modifiers are emitted unconditionally.","solutions":["Remove either the optional ('?') or the negation ('!') modifier — decide whether the node should be optionally present or definitively absent.","If the intent is 'fail if this node exists', keep negation and drop optionality (negation already implies the absence check).","If the intent is 'match with or without this node', keep optionality and drop negation, or express it with an alternative ':' branch.","Catch the RuntimeException at pattern-build time and report which pattern fragment combined the two modifiers."],"exampleFix":"// before\nSemgrexPattern.compile(\"{}=a ?!\"); // optional + negated via ModRelation\n// after\nSemgrexPattern.compile(\"{}=a !\"); // keep only negation\nSemgrexPattern.compile(\"{}=a ?\"); // or keep only optionality","handlingStrategy":"validation","validationCode":"if (pattern.isNegated() && pattern.isOptional()) throw new IllegalArgumentException(\"Node is both negated and optional\");","typeGuard":null,"tryCatchPattern":"try { pattern.negate(); } catch (RuntimeException e) { throw new IllegalArgumentException(\"Conflicting ?/! modifiers on node\", e); }","preventionTips":["Never combine '?' and '!' on the same node","Check isNegated()/isOptional() before setting the other flag in builders","Express alternatives with ':' branches instead of mixed modifiers"],"tags":["java","semgrex","invalid-state","pattern"],"backgroundTag":"invalid-state-transition","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"}