{"record":{"id":"dfc705276bdaa7f5","repo":"apache/hadoop","slug":"key-class-or-comparator-option-must-be-set","errorCode":null,"errorMessage":"key class or comparator option must be set","messagePattern":"key class or comparator option must be set","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/MapFile.java","lineNumber":322,"sourceCode":"        CompressionCodec codec) {\n      return SequenceFile.Writer.compression(type, codec);\n    }\n\n    public static SequenceFile.Writer.Option progressable(Progressable value) {\n      return SequenceFile.Writer.progressable(value);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public Writer(Configuration conf, \n                  Path dirName,\n                  SequenceFile.Writer.Option... opts\n                  ) throws IOException {\n      KeyClassOption keyClassOption = \n        Options.getOption(KeyClassOption.class, opts);\n      ComparatorOption comparatorOption =\n        Options.getOption(ComparatorOption.class, opts);\n      if ((keyClassOption == null) == (comparatorOption == null)) {\n        throw new IllegalArgumentException(\"key class or comparator option \"\n                                           + \"must be set\");\n      }\n      this.indexInterval = conf.getInt(INDEX_INTERVAL, this.indexInterval);\n\n      Class<? extends WritableComparable> keyClass;\n      if (keyClassOption == null) {\n        this.comparator = comparatorOption.getValue();\n        keyClass = comparator.getKeyClass();\n      } else {\n        keyClass= \n          (Class<? extends WritableComparable>) keyClassOption.getValue();\n        this.comparator = WritableComparator.get(keyClass, conf);\n      }\n      this.lastKey = comparator.newKey();\n      FileSystem fs = dirName.getFileSystem(conf);\n\n      if (!fs.mkdirs(dirName)) {\n        throw new IOException(\"Mkdirs failed to create directory \" + dirName);","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/MapFile.java#L304-L340","documentation":"Thrown by the MapFile.Writer(Configuration, Path, Option...) constructor when KeyClassOption and ComparatorOption are either both absent or both present — the condition ((keyClassOption == null) == (comparatorOption == null)) enforces exactly one. MapFile needs to know the key type either directly (keyClass option) or indirectly (a comparator whose getKeyClass() supplies it); giving neither leaves the sort order undefined, and giving both is contradictory.","triggerScenarios":"new MapFile.Writer(conf, dir) with only Writer.valueClass(...) or file(...) options; passing both MapFile.Writer.keyClass(Text.class) and MapFile.Writer.comparator(comparator) at once. Note SetFile.Writer and subclass constructors route through this check too.","commonSituations":"Porting old MapFile.Writer code that used the deprecated String keyClass/valueClass constructor to the Option-based API and dropping the key class argument; copy-pasting an example that included a comparator while your code already sets the key class.","solutions":["Pass exactly one of the two: the common fix is adding Writer.keyClass(YourKey.class) alongside Writer.valueClass(...).","If you need a custom ordering, keep only Writer.comparator(cmp) — the key class is then taken from cmp.getKeyClass().","Remove whichever of the two options you duplicated before retrying construction."],"exampleFix":"// before: no key class or comparator\nnew MapFile.Writer(conf, new Path(\"out\"),\n    MapFile.Writer.valueClass(Text.class)); // throws\n\n// after: exactly one way to determine the key class\nnew MapFile.Writer(conf, new Path(\"out\"),\n    MapFile.Writer.keyClass(Text.class),\n    MapFile.Writer.valueClass(Text.class));","handlingStrategy":"validation","validationCode":"boolean hasKey = Arrays.stream(opts).anyMatch(o -> o instanceof MapFile.Writer.KeyClassOption);\nboolean hasCmp = Arrays.stream(opts).anyMatch(o -> o instanceof MapFile.Writer.ComparatorOption);\nif (hasKey == hasCmp) {\n  throw new IllegalArgumentException(\"Pass exactly one of keyClass or comparator\");\n}\nnew MapFile.Writer(conf, dir, opts);","typeGuard":null,"tryCatchPattern":"try {\n  writer = new MapFile.Writer(conf, dir, opts);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"key class or comparator\")) {\n    throw new IllegalStateException(\"MapFile.Writer misconfigured\", e);\n  }\n  throw e;\n}","preventionTips":["Wrap MapFile.Writer construction in a factory method that always sets keyClass (or comparator) once.","Migrating off the deprecated (conf, dir, keyClass, valueClass) constructor? Move BOTH class arguments into Writer.keyClass/valueClass options.","Review any code path that builds the Option... array dynamically — an empty or over-specified array is the usual bug."],"tags":["mapfile","constructor","options","hadoop-common"],"backgroundTag":"missing-required-option","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}