{"record":{"id":"c0309e35da35f824","repo":"stanfordnlp/CoreNLP","slug":"cannot-make-an-editnode-with-no-updated-attributes","errorCode":null,"errorMessage":"Cannot make an EditNode with no updated attributes, removed attributes, or updated/removed morphological features","messagePattern":"Cannot make an EditNode with no updated attributes, removed attributes, or updated/removed morphological features","errorType":"exception","errorClass":"SsurgeonParseException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/EditNode.java","lineNumber":37,"sourceCode":" * Edit an existing node to have new attributes.\n *\n * @author John Bauer\n */\npublic class EditNode extends SsurgeonEdit {\n  public static final String LABEL = \"editNode\";\n\n  final String nodeName;\n  final List<String> removedAttributes;\n  final List<String> removedMorpho;\n  final Map<String, String> attributes;\n  final Map<String, String> updateMorphoFeatures;\n\n  public EditNode(String nodeName, Map<String, String> attributes, String updateMorphoFeatures, List<String> removedAttributes, List<String> removedMorpho) {\n    if (nodeName == null) {\n      throw new SsurgeonParseException(\"Cannot make an EditNode with no nodeName\");\n    }\n    if (attributes.size() == 0 && updateMorphoFeatures == null && removedAttributes.size() == 0 && removedMorpho.size() == 0) {\n      throw new SsurgeonParseException(\"Cannot make an EditNode with no updated attributes, removed attributes, or updated/removed morphological features\");\n    }\n    AddDep.checkIllegalAttributes(attributes);\n    this.nodeName = nodeName;\n    this.attributes = new TreeMap<>(attributes);\n    if (updateMorphoFeatures != null) {\n      this.updateMorphoFeatures = new CoNLLUFeatures(updateMorphoFeatures);\n    } else {\n      this.updateMorphoFeatures = Collections.emptyMap();\n    }\n    this.removedAttributes = new ArrayList<>(removedAttributes);\n    for (String attr : removedAttributes) {\n      if (AnnotationLookup.toCoreKey(attr) == null) {\n        throw new SsurgeonParseException(\"Unknown attribute |\" + attr + \"| when building an EditNode operation\");\n      }\n    }\n    this.removedMorpho = new ArrayList<>(removedMorpho);\n  }\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/EditNode.java#L19-L55","documentation":"An EditNode must actually change something. If the attributes map is empty, updateMorphoFeatures is null, and both removed lists are empty, the constructor throws SsurgeonParseException because the operation would be a no-op on the matched node.","triggerScenarios":"new EditNode(\"node\", Map.of(), null, List.of(), List.of()) — an editnode rule whose -attributes, -updateMorphoFeatures, -removeAttributes, and -removeMorphoFeatures are all absent/empty.","commonSituations":"Generating editnode instructions from templates where all optional fields default to empty; editing .ssurgeon files and stripping all attribute arguments while leaving the instruction in place.","solutions":["Add at least one attribute to set, one attribute to remove, or morphological features to update/remove.","Remove the editnode instruction from the rule entirely if no edit is intended.","In rule-generation code, skip emitting editnode when all edit payloads are empty."],"exampleFix":"// before\nnew EditNode(\"noun\", Map.of(), null, List.of(), List.of()); // no-op\n\n// after\nnew EditNode(\"noun\", Map.of(\"lemma\", \"dog\"), null, List.of(), List.of());","handlingStrategy":"validation","validationCode":"// Java\nboolean hasEdit = !attrs.isEmpty() || updateMorphoFeatures != null\n    || !removedAttrs.isEmpty() || !removedMorpho.isEmpty();\nif (!hasEdit) {\n  throw new IllegalArgumentException(\"EditNode would be a no-op; provide at least one edit\");\n}","typeGuard":null,"tryCatchPattern":"// Java\ntry {\n  EditNode op = new EditNode(node, attrs, morpho, removedAttrs, removedMorpho);\n} catch (SsurgeonParseException e) {\n  log.warning(\"Dropping no-op editnode rule: \" + e.getMessage());\n}","preventionTips":["Skip emitting editnode instructions whose fields are all empty in generated rules.","Audit .ssurgeon files for editnode lines left with no attribute arguments."],"tags":["java","ssurgeon","validation","no-op"],"backgroundTag":"empty-required-field","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}