{"record":{"id":"69f532491fdf7a7c","repo":"stanfordnlp/CoreNLP","slug":"we-need-at-least-2-extractors-for-extractormerger","errorCode":null,"errorMessage":"We need at least 2 extractors for ExtractorMerger to make sense.","messagePattern":"We need at least 2 extractors for ExtractorMerger to make sense\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/ie/machinereading/ExtractorMerger.java","lineNumber":31,"sourceCode":"import edu.stanford.nlp.ling.CoreAnnotations;\nimport edu.stanford.nlp.pipeline.Annotation;\nimport edu.stanford.nlp.util.CoreMap;\n\n/**\n * Simple extractor which combines several other Extractors.  Currently only works with RelationMentions.\n * Also note that this implementation uses Sets and will mangle the original order of RelationMentions.\n *\n * @author David McClosky\n */\npublic class ExtractorMerger implements Extractor {\n\n  private static final long serialVersionUID = 1L;\n  private static final Logger logger = Logger.getLogger(ExtractorMerger.class.getName());\n  private Extractor[] extractors;\n\n  public ExtractorMerger(Extractor[] extractors) {\n    if (extractors.length < 2) {\n      throw new IllegalArgumentException(\"We need at least 2 extractors for ExtractorMerger to make sense.\");\n    }\n    this.extractors = extractors;\n  }\n\n  @Override\n  public void annotate(Annotation dataset) {\n    // TODO for now, we only merge RelationMentions\n    logger.info(\"Extractor 0 annotating dataset.\");\n    extractors[0].annotate(dataset);\n\n    // store all the RelationMentions per sentence\n    List<Set<RelationMention>> allRelationMentions = new ArrayList<>();\n    for (CoreMap sentence : dataset.get(CoreAnnotations.SentencesAnnotation.class)) {\n      List<RelationMention> relationMentions = sentence.get(MachineReadingAnnotations.RelationMentionsAnnotation.class);\n      Set<RelationMention> uniqueRelationMentions = new HashSet<>(relationMentions);\n      allRelationMentions.add(uniqueRelationMentions);\n    }\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/ie/machinereading/ExtractorMerger.java#L13-L49","documentation":"The ExtractorMerger constructor validates its input: it exists solely to merge the output of multiple extractors, so an array with fewer than 2 extractors is meaningless and throws IllegalArgumentException. This is a fail-fast constructor argument check.","triggerScenarios":"Calling new ExtractorMerger(new Extractor[0]) or new ExtractorMerger(new Extractor[]{oneExtractor}) — i.e. constructing the merger with an empty or single-element extractor array (also a null array, via NPE on .length).","commonSituations":"Building an extractor list from config that filtered down to one (or zero) extractors; accidental array slicing/concatenation bug; code that unconditionally wraps in ExtractorMerger even when only one extractor is enabled.","solutions":["Only construct ExtractorMerger when you actually have two or more extractors to combine.","Add a guard: if extractors.length == 1 use it directly instead of wrapping it in a merger.","Fix the config/assembly code that produced fewer than 2 extractors (check for silently filtered-out entries).","Null-check the array before the length check to convert a potential NPE into a clear error."],"exampleFix":"// before\nExtractorMerger merger = new ExtractorMerger(extractors);\n// after\nExtractor extractor = extractors.length == 1 ? extractors[0] : new ExtractorMerger(extractors);","handlingStrategy":"validation","validationCode":"if (extractors == null || extractors.length < 2) {\n  throw new IllegalArgumentException(\"ExtractorMerger requires at least 2 extractors\");\n}","typeGuard":"boolean mergable(Extractor[] extractors) {\n  return extractors != null && extractors.length >= 2;\n}","tryCatchPattern":"try {\n  extractor = new ExtractorMerger(extractors);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"at least 2 extractors\")) {\n    extractor = extractors.length == 1 ? extractors[0] : null;\n    return;\n  }\n  throw e;\n}","preventionTips":["Check the assembled extractor list size before wrapping it in ExtractorMerger.","Use a builder/factory that falls back to a single extractor when only one is configured.","Log configured extractors at startup to catch silent filtering."],"tags":["java","constructor","validation"],"backgroundTag":"invalid-constructor-argument","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"}