{"record":{"id":"7792c70dafe402be","repo":"apache/hadoop","slug":"child-value-classes-fail-to-agree","errorCode":null,"errorMessage":"Child value classes fail to agree","messagePattern":"Child value classes fail to agree","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/MultiFilterRecordReader.java","lineNumber":101,"sourceCode":"      jc.reset(iterkey);\n      if (jc.flush(ivalue)) {\n        WritableUtils.cloneInto(key, jc.key());\n        WritableUtils.cloneInto(value, emit(ivalue));\n        return true;\n      }\n      jc.clear();\n    }\n    return false;\n  }\n\n  /** {@inheritDoc} */\n  @SuppressWarnings(\"unchecked\") // Explicit check for value class agreement\n  public V createValue() {\n    if (null == valueclass) {\n      final Class<?> cls = kids[0].createValue().getClass();\n      for (RecordReader<K,? extends V> rr : kids) {\n        if (!cls.equals(rr.createValue().getClass())) {\n          throw new ClassCastException(\"Child value classes fail to agree\");\n        }\n      }\n      valueclass = cls.asSubclass(Writable.class);\n      ivalue = createInternalValue();\n    }\n    return (V) ReflectionUtils.newInstance(valueclass, null);\n  }\n\n  /**\n   * Return an iterator returning a single value from the tuple.\n   * @see MultiFilterDelegationIterator\n   */\n  protected ResetableIterator<V> getDelegate() {\n    return new MultiFilterDelegationIterator();\n  }\n\n  /**\n   * Proxy the JoinCollector, but include callback to emit.","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/MultiFilterRecordReader.java#L83-L119","documentation":"MultiFilterRecordReader, the base of override-style joins (OverrideRecordReader), emits a single child value per record instead of a TupleWritable, so all children must share one value class. createValue() throws ClassCastException(\"Child value classes fail to agree\") when the child RecordReaders return different value classes. It fires on the first createValue() call during task setup.","triggerScenarios":"An override(...) join whose tbl(...) sources produce different value classes, e.g. SequenceFile Text values against a custom Writable; any custom reader extending MultiFilterRecordReader whose children disagree on their value class.","commonSituations":"Using override to co-group sources written by different jobs or serializations; one source regenerated with a new schema while the others kept the old one.","solutions":["Re-emit the mismatched source with a map-only job so all children share one value class","Use the same InputFormat and serialization for every source in the override expression","Switch the outer node from override to inner/outer when a TupleWritable value is acceptable, since tuple joins tolerate per-child value classes"],"exampleFix":"// before: override requires one shared value class, sources differ\njob.set(\"mapred.join.expr\", \"override(tbl(SequenceFileInputFormat,/old),tbl(SequenceFileInputFormat,/new))\");\n\n// after: normalize values, or use outer(...) which emits TupleWritable\njob.set(\"mapred.join.expr\",\n    CompositeInputFormat.compose(\"outer\", SequenceFileInputFormat.class, \"/old\", \"/new\"));","handlingStrategy":"type-guard","validationCode":"FileSystem fs = FileSystem.get(conf);\nSet<Class<?>> valueClasses = new HashSet<Class<?>>();\nfor (Path p : joinSources) {\n  SequenceFile.Reader r = new SequenceFile.Reader(fs, p, conf);\n  try {\n    valueClasses.add(r.getValueClass());\n  } finally {\n    r.close();\n  }\n}\nif (valueClasses.size() > 1) {\n  throw new IOException(\"override join requires one shared value class: \" + valueClasses);\n}","typeGuard":"static boolean valuesAgree(ComposableRecordReader<?> a, ComposableRecordReader<?> b) {\n  return a.createValue().getClass().equals(b.createValue().getClass());\n}","tryCatchPattern":"try {\n  V val = rr.createValue();\n} catch (ClassCastException e) {\n  throw new IOException(\"override children must share one value class; \"\n      + \"normalize the sources or use inner/outer\", e);\n}","preventionTips":["For override joins, write every source with the same value serialization","Prefer outer/inner joins when per-source value classes must differ (TupleWritable tolerates them)","Check getValueClass() on all SequenceFile sources before submitting"],"tags":["hadoop","mapreduce","join","classcast","value-type","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}