apache/hadoop · error · IOException
Inconsistent split cardinality from child {} ({}/{})
Error message
Inconsistent split cardinality from child {} ({}/{}) What it means
CNode.getSplits zips the ith split of every child into one CompositeInputSplit, so every source must return exactly the same number of splits; otherwise it throws IOException("Inconsistent split cardinality from child i (a/b)") with the two counts. CompositeInputFormat.getSplits defends against this by forcing job.setLong("mapred.min.split.size", Long.MAX_VALUE) so each file-based child yields a single split — hitting the error means that defense was bypassed or a child InputFormat ignores the setting.
Source
Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:385
for (Node n : kids) {
n.setKeyComparator(cmpcl);
}
}
/**
* Combine InputSplits from child InputFormats into a
* {@link CompositeInputSplit}.
*/
public InputSplit[] getSplits(JobConf job, int numSplits)
throws IOException {
InputSplit[][] splits = new InputSplit[kids.size()][];
for (int i = 0; i < kids.size(); ++i) {
final InputSplit[] tmp = kids.get(i).getSplits(job, numSplits);
if (null == tmp) {
throw new IOException("Error gathering splits from child RReader");
}
if (i > 0 && splits[i-1].length != tmp.length) {
throw new IOException("Inconsistent split cardinality from child " +
i + " (" + splits[i-1].length + "/" + tmp.length + ")");
}
splits[i] = tmp;
}
final int size = splits[0].length;
CompositeInputSplit[] ret = new CompositeInputSplit[size];
for (int i = 0; i < size; ++i) {
ret[i] = new CompositeInputSplit(splits.length);
for (int j = 0; j < splits.length; ++j) {
ret[i].add(splits[j][i]);
}
}
return ret;
}
@SuppressWarnings("unchecked") // child types unknowable
public ComposableRecordReader getRecordReader(
InputSplit split, JobConf job, Reporter reporter) throws IOException {View on GitHub (pinned to 2add963021)
Solutions
- Use CompositeInputFormat (mapred) as the job's InputFormat so its min-split-size forcing applies to all children
- If driving children yourself, set mapred.min.split.size to Long.MAX_VALUE in the JobConf passed to getSplits so each source yields one split
- Make custom child InputFormats honor mapred.min.split.size or otherwise return equal split counts
- Pre-partition all sources identically — same number of similarly sized, identically sorted parts
Example fix
// before: custom driver, unequal split counts
InputSplit[] a = fmtA.getSplits(job, 4); // 4 splits
InputSplit[] b = fmtB.getSplits(job, 1); // 1 split -> inconsistent cardinality
// after: one split per source, exactly what CompositeInputFormat.getSplits does
job.setLong("mapred.min.split.size", Long.MAX_VALUE);
InputSplit[] a = fmtA.getSplits(job, 1);
InputSplit[] b = fmtB.getSplits(job, 1); Defensive patterns
Strategy: validation
Validate before calling
// preflight: force one split per source (exactly what CompositeInputFormat does)
job.setLong("mapred.min.split.size", Long.MAX_VALUE);
for (int i = 0; i < kids; i++) {
InputSplit[] s = childFormats.get(i).getSplits(job, 1);
if (i > 0 && s.length != prevLen) {
throw new IOException("child " + i + " yields " + s.length
+ " splits vs " + prevLen + " from child 0");
}
prevLen = s.length;
} Try / catch
try {
return cif.getSplits(job, numSplits);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("cardinality")) {
throw new IOException("join sources produced unequal split counts; "
+ "set mapred.min.split.size=Long.MAX_VALUE or repartition inputs", e);
}
throw e;
} Prevention
- Use CompositeInputFormat as the InputFormat so its min-split-size forcing applies
- Make custom child InputFormats honor mapred.min.split.size
- Keep join inputs partitioned identically (same part count and similar sizes)
When it happens
Trigger: Driving Parser nodes directly instead of through CompositeInputFormat.getSplits; a child InputFormat (custom, or database-style) that computes splits from its own hints and ignores mapred.min.split.size; children reading inputs with very different file sizes or block counts so their split counts differ.
Common situations: Joining one large source with one small source and expecting the framework to re-shard them; custom input formats inside tbl(...); a hand-rolled driver replacing CompositeInputFormat; inputs with different replication of many small files.
Related errors
- Too many splits
- Invalid split type:{}
- Uninitialized InputSplit
- Child key classes fail to agree
- Child value classes fail to agree
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/c7785fabf376a2d6.
Report an issue: GitHub.