apache/beam · error · IllegalStateException

Metadata value type must be one of String, Long, or byte[]…

Error message

Metadata value type must be one of String, Long, or byte[]. Found ${v.getClass().getSimpleName()}

What it means

AvroSink (the file-based sink used by AvroIO.Write) validates metadata map values when preparing the writer: only String, Long, and byte[] are accepted by Avro's DataFileWriter.setMeta. Any other type throws IllegalStateException.

Solutions

  1. Normalize metadata values to String, Long, or byte[] before building the Write transform
  2. Replace boxed Integer values with Long
  3. Convert unsupported types to their String representation

Example fix

// before
metadata.put("ratio", 0.5);
// after
metadata.put("ratio", "0.5");
Defensive patterns

Strategy: type-guard

Validate before calling

for (Map.Entry<String, Object> e : metadata.entrySet()) {
  Object v = e.getValue();
  if (!(v instanceof String || v instanceof Long || v instanceof byte[]))
    throw new IllegalArgumentException(e.getKey() + " is " + v.getClass());
}

Type guard

static boolean validMeta(Object v) {
  return v instanceof String || v instanceof Long || v instanceof byte[];
}

Try / catch

try { sink.prepareWrite(...); } catch (IllegalStateException e) { /* sanitize metadata map */ }

Prevention

When it happens

Trigger: Providing a metadata map with values like Integer, Float, or Boolean to the AvroSink used by AvroIO.Write; thrown during prepareWrite on workers.

Common situations: Same as the AvroIO variant: autoboxed integers, deserialized JSON config where numbers became Integer, dynamically built metadata maps.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/5a24f007f0f46453. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/extensions/avro/src/main/java/org/apache/beam/sdk/extensions/avro/io/AvroSink.java:134

      CodecFactory codec = dynamicDestinations.getCodec(destination);
      Schema schema = dynamicDestinations.getSchema(destination);
      Map<String, Object> metadata = dynamicDestinations.getMetadata(destination);
      DatumWriter<OutputT> datumWriter =
          Optional.ofNullable(dynamicDestinations.getDatumWriterFactory(destination))
              .orElse(AvroDatumFactory.of(type))
              .apply(schema);

      dataFileWriter = new DataFileWriter<>(datumWriter).setCodec(codec);
      for (Map.Entry<String, Object> entry : metadata.entrySet()) {
        Object v = entry.getValue();
        if (v instanceof String) {
          dataFileWriter.setMeta(entry.getKey(), (String) v);
        } else if (v instanceof Long) {
          dataFileWriter.setMeta(entry.getKey(), (Long) v);
        } else if (v instanceof byte[]) {
          dataFileWriter.setMeta(entry.getKey(), (byte[]) v);
        } else {
          throw new IllegalStateException(
              "Metadata value type must be one of String, Long, or byte[]. Found "
                  + v.getClass().getSimpleName());
        }
      }
      dataFileWriter.setSyncInterval(syncInterval);
      dataFileWriter.create(schema, Channels.newOutputStream(channel));
    }

    @Override
    public void write(OutputT value) throws Exception {
      dataFileWriter.append(value);
    }

    @Override
    protected void finishWrite() throws Exception {
      dataFileWriter.flush();
    }
  }

View on GitHub (pinned to 12126d8942)