{"record":{"id":"b12a5c0ff88dc567","repo":"apache/hadoop","slug":"expression-is-null","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/mapred/join/Parser.java","lineNumber":479,"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, job);\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, JobConf job) throws IOException {\n    if (null == expr) {\n      throw new IOException(\"Expression is null\");\n    }\n    Class<? extends WritableComparator> cmpcl =\n      job.getClass(\"mapred.join.keycomparator\", 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, job));\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":461,"sourceCodeEnd":497,"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/Parser.java#L461-L497","documentation":"CompositeInputFormat.setFormat passes job.get(\"mapred.join.expr\") to Parser.parse, which throws IOException(\"Expression is null\") when the property is unset. The join expression is mandatory: without it there is no parse tree and the job can neither compute splits nor readers. The mapreduce-API variant reads \"mapreduce.join.expr\" instead, so setting the wrong API's property also lands here.","triggerScenarios":"Submitting a job with CompositeInputFormat as InputFormat but never setting mapred.join.expr; setting mapred.join.expr on a JobConf other than the one used for submission; using org.apache.hadoop.mapreduce.lib.join.CompositeInputFormat while setting only mapred.join.expr (or vice versa).","commonSituations":"Mixing the old (mapred) and new (mapreduce.lib.join) join APIs; the property set after the job was submitted; copy-paste jobs missing the compose/set step; property name typos.","solutions":["Set the expression before submission: job.set(\"mapred.join.expr\", CompositeInputFormat.compose(\"inner\", fmt, paths)) — or CompositeInputFormat.JOIN_EXPR with the mapreduce variant","Set it on the same JobConf handed to the job client, before getSplits/getRecordReader run","Fail fast client-side: check job.get(\"mapred.join.expr\") != null before submitting"],"exampleFix":"// before\njob.setInputFormat(CompositeInputFormat.class);\n// expression never set -> Expression is null at setFormat time\n\n// after\njob.setInputFormat(CompositeInputFormat.class);\njob.set(\"mapred.join.expr\",\n    CompositeInputFormat.compose(\"inner\", SequenceFileInputFormat.class, \"/a\", \"/b\"));","handlingStrategy":"validation","validationCode":"String expr = CompositeInputFormat.compose(\"inner\",\n    SequenceFileInputFormat.class, \"/a\", \"/b\");\njob.set(\"mapred.join.expr\", expr);\nif (job.get(\"mapred.join.expr\") == null) {\n  throw new IllegalArgumentException(\"mapred.join.expr must be set before submission\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  new CompositeInputFormat<Object>().setFormat(job);\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"null\")) {\n    throw new IllegalArgumentException(\n        \"mapred.join.expr not set (or set on the wrong JobConf/API)\", e);\n  }\n  throw e;\n}","preventionTips":["Set the expression with compose() on the same JobConf used for submission","Match property to API: mapred.join.expr for mapred, mapreduce.join.expr for mapreduce.lib.join","Add a null check on the property in job-construction code"],"tags":["hadoop","mapreduce","join","configuration","missing-property"],"backgroundTag":"missing-required-configuration","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}