{"record":{"id":"446b93c490a22d7c","repo":"stanfordnlp/CoreNLP","slug":"duplicate-attribute-found-in-semgrex-expression","errorCode":null,"errorMessage":"Duplicate attribute  found in semgrex expression","messagePattern":"Duplicate attribute  found in semgrex expression","errorType":"validation","errorClass":"SemgrexParseException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/semgraph/semgrex/NodeAttributes.java","lineNumber":65,"sourceCode":"    this.root = root;\n  }\n\n  public boolean root() {\n    return root;\n  }\n\n  public void setEmpty(boolean empty) {\n    this.empty = empty;\n  }\n\n  public boolean empty() {\n    return empty;\n  }\n\n  public void setAttribute(String key, String value, boolean negated) {\n    if (!negated) {\n      if (positiveAttributes.contains(key)) {\n        throw new SemgrexParseException(\"Duplicate attribute \" + key + \" found in semgrex expression\");\n      }\n      positiveAttributes.add(key);\n    }\n    attributes.add(new Triple(key, value, negated));\n  }\n\n  public void addContains(String annotation, String key, String value, Boolean negated) {\n    contains.add(new Quadruple(annotation, key, value, negated));\n  }\n\n  public List<Triple<String, String, Boolean>> attributes() {\n    return Collections.unmodifiableList(attributes);\n  }\n\n  public List<Quadruple<String, String, String, Boolean>> contains() {\n    return Collections.unmodifiableList(contains);\n  }\n}","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/semgraph/semgrex/NodeAttributes.java#L47-L83","documentation":"NodePattern.setAttribute (used by NodeAttributes) tracks positive (non-negated) attribute keys; setting the same key twice in one semgrex node is ambiguous, so it throws SemgrexParseException. Negated attributes are exempt from the duplicate check.","triggerScenarios":"Calling setAttribute twice with the same key and negated=false on the same node's attribute builder, or writing a semgrex node with a repeated positive attribute (e.g. '[word foo word bar]').","commonSituations":"Hand-written semgrex patterns repeating an attribute, generated patterns from templates where a key is substituted twice, or programmatic AddAttribute calls in a loop without deduplication.","solutions":["Remove the duplicate attribute from the node expression, merging values if possible","Use a coordination/disanjunctive form if two values for one key were intended","Deduplicate keys programmatically before calling AddAttribute/setAttribute"],"exampleFix":"// before\nnode.addAttribute(\"word\", \"foo\", false); node.addAttribute(\"word\", \"bar\", false);\n// after\nnode.addAttribute(\"word\", \"foo\", false); node.addAttribute(\"tag\", \"bar\", false);","handlingStrategy":"validation","validationCode":"Set<String> seen = new HashSet<>(); for (Triple<String,String,Boolean> a : attrs) if (!a.third() && !seen.add(a.first())) throw new IllegalArgumentException(\"Duplicate attribute \" + a.first());","typeGuard":null,"tryCatchPattern":"try { nodeAttributes.setAttribute(key, value, negated); } catch (SemgrexParseException e) { log.error(e.getMessage()); }","preventionTips":["Deduplicate attribute keys before building a node","Merge repeated keys with disjunction instead of repeating them","Validate generated patterns with a dry parse in CI"],"tags":["java","semgrex","duplicate-key","validation"],"backgroundTag":"conflicting-config-options","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"}