{"record":{"id":"da575bd6ae12c605","repo":"apache/hadoop","slug":"expression-is-null-da575b","errorCode":null,"errorMessage":"Expression is null","messagePattern":"Expression is null","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":542,"sourceCode":"    if (st.isEmpty()) {\n      throw new IOException(\"Unmatched ')'\");\n    }\n    st.pop();\n    if (st.isEmpty() || !TType.IDENT.equals(st.peek().getType())) {\n      throw new IOException(\"Identifier expected\");\n    }\n    Node n = Node.forIdent(st.pop().getStr());\n    n.parse(args, conf);\n    return new NodeToken(n);\n  }\n\n  /**\n   * Given an expression and an optional comparator, build a tree of\n   * InputFormats using the comparator to sort keys.\n   */\n  static Node parse(String expr, Configuration conf) throws IOException {\n    if (null == expr) {\n      throw new IOException(\"Expression is null\");\n    }\n    Class<? extends WritableComparator> cmpcl = conf.getClass(\n      CompositeInputFormat.JOIN_COMPARATOR, null, WritableComparator.class);\n    Lexer lex = new Lexer(expr);\n    Stack<Token> st = new Stack<Token>();\n    Token tok;\n    while ((tok = lex.next()) != null) {\n      if (TType.RPAREN.equals(tok.getType())) {\n        st.push(reduce(st, conf));\n      } else {\n        st.push(tok);\n      }\n    }\n    if (st.size() == 1 && TType.CIF.equals(st.peek().getType())) {\n      Node ret = st.pop().getNode();\n      if (cmpcl != null) {\n        ret.setKeyComparator(cmpcl);\n      }","sourceCodeStart":524,"sourceCodeEnd":560,"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#L524-L560","documentation":"CompositeInputFormat.setFormat reads the join expression from the 'mapreduce.join.expr' property and hands it to Parser.parse (Parser.java:545-547). If the property is unset (conf.get returns null), the parser immediately throws 'Expression is null'. It means the job never defined its join expression.","triggerScenarios":"Using CompositeInputFormat as the job's InputFormat (job.setInputFormatClass or the mapred equivalent) without calling CompositeInputFormat.setFormat or setting 'mapreduce.join.expr'; setting the property on a different Configuration instance than the one the job uses; relying on mapred.join.expr (old API name) with the new API parser.","commonSituations":"New join jobs missing the expression setup line; refactors that drop the conf.set(\"mapreduce.join.expr\", ...) call; copying examples that use the old mapred API (org.apache.hadoop.mapred.join.CompositeInputFormat uses 'mapred.join.expr') into new-API code; configuration set on the job's Configuration after Job submission or on a template conf that is not propagated.","solutions":["Set the expression before submission: job.getConfiguration().set(\"mapreduce.join.expr\", CompositeInputFormat.compose(\"inner\", TextInputFormat.class, \"/a\", \"/b\"))","Or call new CompositeInputFormat<>().setFormat(conf) after the property is set (it also registers default identifiers)","Verify you use the new-API property name mapreduce.join.expr (old API: mapred.join.expr in org.apache.hadoop.mapred.join)","Print/log conf.get(\"mapreduce.join.expr\") right before job.submit() to confirm it is non-null on the submitted config"],"exampleFix":"// before\njob.setInputFormatClass(CompositeInputFormat.class);\n// forgot the expression -> 'Expression is null' at getSplits/createRecordReader time\n\n// after\njob.setInputFormatClass(CompositeInputFormat.class);\njob.getConfiguration().set(\"mapreduce.join.expr\",\n  CompositeInputFormat.compose(\"inner\", TextInputFormat.class, \"/join/a\", \"/join/b\"));","handlingStrategy":"validation","validationCode":"static Configuration withJoinExpr(Configuration conf, String op, Class<? extends InputFormat<?>> inf, String... paths) {\n  if (conf.get(\"mapreduce.join.expr\") == null)\n    conf.set(\"mapreduce.join.expr\", CompositeInputFormat.compose(op, inf, paths));\n  return conf;\n}","typeGuard":null,"tryCatchPattern":"try { cif.getSplits(job); } catch (IOException e) { if (\"Expression is null\".equals(e.getMessage())) throw new IllegalStateException(\"mapreduce.join.expr not set — configure the join expression in the driver\", e); throw e; }","preventionTips":["Always set mapreduce.join.expr (new API) or mapred.join.expr (old API) when using CompositeInputFormat","Set it on the exact Configuration the Job wraps, before submit","Unit-test the driver: assert conf.get(\"mapreduce.join.expr\") is non-null after setup"],"tags":["hadoop","mapreduce","join","configuration","missing-property"],"backgroundTag":"missing-config-property","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}