{"record":{"id":"77bf43289a015df1","repo":"apache/hadoop","slug":"error-gathering-splits-from-child-rreader-77bf43","errorCode":null,"errorMessage":"Error gathering splits from child RReader","messagePattern":"Error gathering splits from child RReader","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/join/Parser.java","lineNumber":441,"sourceCode":"      super.setKeyComparator(cmpcl);\n      for (Node n : kids) {\n        n.setKeyComparator(cmpcl);\n      }\n    }\n\n    /**\n     * Combine InputSplits from child InputFormats into a\n     * {@link CompositeInputSplit}.\n     */\n    @SuppressWarnings(\"unchecked\")\n\tpublic List<InputSplit> getSplits(JobContext job)\n        throws IOException, InterruptedException {\n      List<List<InputSplit>> splits = \n        new ArrayList<List<InputSplit>>(kids.size());\n      for (int i = 0; i < kids.size(); ++i) {\n        List<InputSplit> tmp = kids.get(i).getSplits(job);\n        if (null == tmp) {\n          throw new IOException(\"Error gathering splits from child RReader\");\n        }\n        if (i > 0 && splits.get(i-1).size() != tmp.size()) {\n          throw new IOException(\"Inconsistent split cardinality from child \" +\n              i + \" (\" + splits.get(i-1).size() + \"/\" + tmp.size() + \")\");\n        }\n        splits.add(i, tmp);\n      }\n      final int size = splits.get(0).size();\n      List<InputSplit> ret = new ArrayList<InputSplit>();\n      for (int i = 0; i < size; ++i) {\n        CompositeInputSplit split = new CompositeInputSplit(splits.size());\n        for (int j = 0; j < splits.size(); ++j) {\n          split.add(splits.get(j).get(i));\n        }\n        ret.add(split);\n      }\n      return ret;\n    }","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/join/Parser.java#L423-L459","documentation":"Parser.CNode.getSplits (Parser.java:441) gathers splits from each child input of a composite join node; if a child InputFormat's getSplits(...) returns null (rather than a list), this IOException is thrown. Standard Hadoop InputFormats throw or return an (possibly empty) list, never null, so this almost always indicates a custom InputFormat breaking the API contract.","triggerScenarios":"A child InputFormat used in tbl(...) overrides getSplits and returns null (e.g. on empty input or error paths); a stub/mock InputFormat in tests returns null; a third-party InputFormat implemented against an older/different contract.","commonSituations":"Custom or third-party InputFormats plugged into CompositeInputFormat joins; unit tests with mocked InputFormats that forget to return Collections.emptyList(); InputFormat wrappers that swallow exceptions and return null instead of propagating.","solutions":["Fix the custom child InputFormat to return an empty list (or throw) from getSplits — never null","If the child is third-party, wrap it in an adapter InputFormat that converts null to an empty list","Test the child InputFormat.getSplits standalone before using it in a join expression","For empty-input handling prefer returning an empty list so the join framework can reason about cardinality"],"exampleFix":"// before (custom InputFormat)\npublic List<InputSplit> getSplits(JobContext ctx) throws IOException {\n  if (inputs.isEmpty()) return null; // triggers 'Error gathering splits from child RReader'\n  ...\n}\n\n// after\npublic List<InputSplit> getSplits(JobContext ctx) throws IOException {\n  if (inputs.isEmpty()) return Collections.emptyList();\n  ...\n}","handlingStrategy":"validation","validationCode":"static List<InputSplit> safeSplits(InputFormat<?,?> inf, JobContext ctx) throws IOException {\n  List<InputSplit> s = inf.getSplits(ctx);\n  return (s == null) ? java.util.Collections.emptyList() : s; // enforce non-null contract in wrappers\n}","typeGuard":null,"tryCatchPattern":"try { return root.getSplits(job); } catch (IOException e) { if (e.getMessage().contains(\"Error gathering splits\")) { throw new IOException(\"Child InputFormat returned null splits — check custom InputFormat contract\", e); } throw e; }","preventionTips":["Custom InputFormats must return empty lists, never null, from getSplits","Wrap third-party InputFormats with a null-to-empty-list adapter before using them in joins","Test child InputFormat.getSplits standalone including the empty-input case"],"tags":["hadoop","mapreduce","join","input-split","null-contract"],"backgroundTag":"null-return-contract-violation","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}