apache/hadoop · error · IOException

Expected quoted string

Error message

Expected quoted string

What it means

After the comma, WNode.parse requires the path argument to be a double-quoted string token (TType.QUOT, produced because Lexer sets quoteChar('"')). Any other token in the path position — an unquoted identifier, a number, or a parenthesis — throws IOException("Expected quoted string").

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/join/Parser.java:304

          try {
          	inf = (InputFormat)ReflectionUtils.newInstance(
          			job.getClassByName(sb.toString()),
                job);
          } catch (ClassNotFoundException e) {
            throw (IOException)new IOException().initCause(e);
          } catch (IllegalArgumentException e) {
            throw (IOException)new IOException().initCause(e);
          }
          break;
        }
        sb.append(t.getStr());
      }
      if (!i.hasNext()) {
        throw new IOException("Parse error");
      }
      Token t = i.next();
      if (!TType.QUOT.equals(t.getType())) {
        throw new IOException("Expected quoted string");
      }
      indir = t.getStr();
      // no check for ll.isEmpty() to permit extension
    }

    private JobConf getConf(JobConf job) {
      JobConf conf = new JobConf(job);
      FileInputFormat.setInputPaths(conf, indir);
      conf.setClassLoader(job.getClassLoader());
      return conf;
    }

    public InputSplit[] getSplits(JobConf job, int numSplits)
        throws IOException {
      return inf.getSplits(getConf(job), numSplits);
    }

    public ComposableRecordReader getRecordReader(

View on GitHub (pinned to 2add963021)

Solutions

  1. Double-quote the path: tbl(F,\"/data/path\")
  2. Use CompositeInputFormat.compose(), which emits the quotes for you
  3. Remember the grammar: tbl(<class>,\"<path>\") — nothing else is accepted as the second formal

Example fix

// before
job.set("mapred.join.expr", "inner(tbl(F,/a),tbl(F,/b))");

// after
job.set("mapred.join.expr",
    CompositeInputFormat.compose("inner", SequenceFileInputFormat.class, "/a", "/b"));
Defensive patterns

Strategy: validation

Validate before calling

String expr = CompositeInputFormat.compose("inner",
    SequenceFileInputFormat.class, "/a", "/b"); // compose() always quotes paths
if (!expr.matches("[^\"]*\"[^\"]*\"[^\"]*\\).*")) {
  // lightweight sanity: at least one quoted path per tbl clause
}
job.set("mapred.join.expr", expr);

Type guard

boolean isQuotedString(Parser.Token t) {
  return Parser.TType.QUOT.equals(t.getType()); // only double-quoted strings
}

Try / catch

try {
  new CompositeInputFormat<Object>().setFormat(job);
} catch (IOException e) {
  throw new IllegalArgumentException(
      "tbl() path argument must be a double-quoted string", e);
}

Prevention

When it happens

Trigger: tbl(F,/data/path) with an unquoted path; tbl(F,'/data') with single quotes, which the lexer does not treat as string delimiters; a number or parenthesis where the path should be.

Common situations: Forgetting that only double quotes delimit strings in this grammar; unquoted HDFS paths (which can also hit the '/' comment behavior and parse weirdly); expressions edited from shell snippets where the inner quotes were stripped.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/32236553e7ddc13f. Report an issue: GitHub.