apache/beam · error · CoderException

EOF encountered decoding a ValueKind

Error message

EOF encountered decoding a ValueKind

What it means

ValueKindCoder.decode reads a single byte; -1 means the stream has ended with no ValueKind to read. The coder wraps the EOFException in a CoderException so callers can distinguish premature stream end from corrupt data. This indicates truncation or decoding past the last element.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/coders/ValueKindCoder.java:59

  private static final ValueKindCoder INSTANCE = new ValueKindCoder();
  private static final TypeDescriptor<ValueKind> TYPE_DESCRIPTOR =
      TypeDescriptor.of(ValueKind.class);

  private ValueKindCoder() {}

  @Override
  public void encode(ValueKind value, OutputStream outStream) throws IOException, CoderException {
    if (value == null) {
      throw new CoderException("cannot encode a null ValueKind");
    }
    outStream.write(ValueKindUtil.toProto(value).getNumber());
  }

  @Override
  public ValueKind decode(InputStream inStream) throws IOException, CoderException {
    int number = inStream.read();
    if (number == -1) {
      throw new CoderException(new EOFException("EOF encountered decoding a ValueKind"));
    }
    Elements.ValueKind.@Nullable Enum proto = Elements.ValueKind.Enum.forNumber(number);
    if (proto == null) {
      throw new CoderException("Unknown ValueKind number: " + number);
    }

    return ValueKindUtil.fromProto(proto);
  }

  @Override
  public boolean consistentWithEquals() {
    return true;
  }

  @Override
  public boolean isRegisterByteSizeObserverCheap(ValueKind value) {
    return true;
  }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Verify writer and reader element counts match (one ValueKind byte per element).
  2. Check transport integrity — compare expected byte counts to detect truncation.
  3. Fix off-by-one loops that call decode more times than encode.
  4. Catch CoderException with an EOFException cause and treat it as end-of-stream or a truncation error.

Example fix

// before
ValueKind k = kindCoder.decode(in);
// after
try {
  ValueKind k = kindCoder.decode(in);
} catch (CoderException e) {
  if (e.getCause() instanceof EOFException) {
    return; // clean end of stream, or flag truncation
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the stream still has at least one byte before decoding
in.mark(1);
boolean empty = in.read() == -1;
in.reset();
if (empty) throw new EOFException("No ValueKind byte available");

Type guard

static boolean hasMoreBytes(InputStream in) throws IOException {
  return in.available() > 0;
}

Try / catch

try {
  ValueKind k = kindCoder.decode(in);
} catch (CoderException e) {
  if (e.getCause() instanceof EOFException) {
    return; // clean end of stream, or flag truncation
  }
  throw e;
}

Prevention

When it happens

Trigger: Reading an empty stream with decode; a stream written with fewer ValueKind bytes than decode attempts; off-by-one in element counts consuming one byte too many; truncated network/file transport of runner metadata.

Common situations: Truncated gRPC/Dataflow harness payloads; custom runner serialization with mismatched buffer counts; replaying partial log/state files cut off mid-record.

Related errors


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