grpc/grpc-java · error · RuntimeException

failure reading serialized stream

Error message

failure reading serialized stream

What it means

Metadata serializes binary values by fully reading an InputStream into bytes (streamToBytes). If reading the stream throws an IOException — stream already consumed, closed, or I/O failure — it is rethrown as an unchecked RuntimeException('failure reading serialized stream'). It indicates corrupted or exhausted input backing a metadata value.

Solutions

  1. Supply a fresh InputStream (or byte[]) for each metadata value; never reuse a consumed stream
  2. Cache the bytes yourself and use a ByteArrayInputStream per serialization
  3. Review custom BinaryMarshaller.stream() implementations for double-read bugs
  4. Catch RuntimeException around metadata construction to fail fast with context

Example fix

// before
Metadata.Key<byte[]> key = Metadata.Key.of("bin", Metadata.BINARY_BYTE_MARSHALLER);
metadata.put(key, sharedInputStream); // reused across calls
// after
metadata.put(key, ByteStreams.toByteArray(freshSource())); // copy bytes once, byte[] marshaller input is fresh
Defensive patterns

Strategy: try-catch

Validate before calling

byte[] bytes = ByteStreams.toByteArray(source); // read once, validate success before attaching to metadata
if (bytes.length == 0 && requireNonEmpty) throw new IllegalArgumentException("empty metadata value");

Try / catch

try {
  metadata.put(binaryKey, value);
} catch (RuntimeException e) {
  if ("failure reading serialized stream".equals(e.getMessage())) {
    throw new IllegalStateException("Metadata stream was consumed or closed; supply a fresh stream per RPC", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Putting a metadata value whose InputStream has already been read/closed (available()==0 or stream at EOF), a custom stream throwing IOException mid-read, or reusing the same InputStream-backed value across multiple RPCs.

Common situations: Reusing a Metadata object or its binary-marshaller streams across retries; passing a stream from an already-drained resource; custom BinaryMarshaller producing streams that throw on second read.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/7e420846c00d0b9e. Report an issue: GitHub.

Appendix: source

Thrown at api/src/main/java/io/grpc/Metadata.java:1048

     * @param value to serialize
     * @return serialized version of value, or null if value cannot be transmitted.
     */
    byte[] toAsciiString(T value);

    /**
     * Parse a serialized metadata value from an ASCII string.
     *
     * @param serialized value of metadata to parse
     * @return a parsed instance of type T
     */
    T parseAsciiString(byte[] serialized);
  }

  private static byte[] streamToBytes(InputStream stream) {
    try {
      return ByteStreams.toByteArray(stream);
    } catch (IOException ioe) {
      throw new RuntimeException("failure reading serialized stream", ioe);
    }
  }
}

View on GitHub (pinned to 64daddc1f3)