apache/hadoop · error · IOException

wrong key class: {} is not {}

Error message

wrong key class: {} is not {}

What it means

Writer.append(Object key, Object val) enforces that key's runtime class is exactly (==, not instanceof) the declared keyClass before serializing; a mismatch throws this IOException naming both classes. Mixing classes would desynchronize the record format since the serializer was built for one specific class, so the writer fails fast instead of producing garbage.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/SequenceFile.java:1473

     * @param val input Writable val.
     * @throws IOException raised on errors performing I/O.
     */
    public void append(Writable key, Writable val)
      throws IOException {
      append((Object) key, (Object) val);
    }

    /**
     * Append a key/value pair.
     * @param key input Object key.
     * @param val input Object val.
     * @throws IOException raised on errors performing I/O.
     */
    @SuppressWarnings("unchecked")
    public synchronized void append(Object key, Object val)
      throws IOException {
      if (key.getClass() != keyClass)
        throw new IOException("wrong key class: "+key.getClass().getName()
                              +" is not "+keyClass);
      if (val.getClass() != valClass)
        throw new IOException("wrong value class: "+val.getClass().getName()
                              +" is not "+valClass);

      buffer.reset();

      // Append the 'key'
      keySerializer.serialize(key);
      int keyLength = buffer.getLength();
      if (keyLength < 0)
        throw new IOException("negative length keys not allowed: " + key);

      // Append the 'value'
      if (compress == CompressionType.RECORD) {
        deflateFilter.resetState();
        compressedValSerializer.serialize(val);
        deflateOut.flush();

View on GitHub (pinned to 2add963021)

Solutions

  1. Align Writer.keyClass(...) with the concrete class actually appended
  2. If you hold a subclass, copy its fields into an instance of the exact declared class before append
  3. Guard with key.getClass() == writer.getKeyClass() before appending (exact check, matching the writer's semantics)

Example fix

// before
Writer w = SequenceFile.createWriter(conf, Writer.file(p),
    Writer.keyClass(LongWritable.class), Writer.valueClass(Text.class));
w.append(new Text("oops"), new Text("v")); // wrong key class: Text is not LongWritable

// after
w.append(new LongWritable(42), new Text("v"));
Defensive patterns

Strategy: type-guard

Validate before calling

if (key.getClass() != w.getKeyClass()) {
  throw new IllegalArgumentException("key " + key.getClass() + " != declared " + w.getKeyClass());
}

Type guard

static boolean isExactKeyClass(SequenceFile.Writer w, Object key) {
  return key != null && key.getClass() == w.getKeyClass();
}

Try / catch

try {
  w.append(key, val);
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("wrong key class")) {
    // record type drift: align writer options or convert the record, then retry
  } else { throw e; }
}

Prevention

When it happens

Trigger: writer.append(new Text("x"), v) on a writer built with Writer.keyClass(LongWritable.class); appending a subclass instance (MyText extends Text) where the header stores Text; call sites whose static types were refactored while the writer options were not.

Common situations: keyClass/valueClass options drifting from the appended records during refactors; erased generics hiding mismatches until runtime; reusable record objects of the wrong concrete type passed from a shared loop.

Related errors


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