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
- Supply a fresh InputStream (or byte[]) for each metadata value; never reuse a consumed stream
- Cache the bytes yourself and use a ByteArrayInputStream per serialization
- Review custom BinaryMarshaller.stream() implementations for double-read bugs
- 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
- Never reuse an InputStream-backed metadata value across RPCs or retries
- Prefer byte[]/ByteArrayInputStream values for binary metadata
- Copy the stream to bytes yourself if the value must be sent multiple times
- Test custom BinaryMarshallers with repeated serialization
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
- AnonymousInProcessSocketAddress is not serializable
- Failed to bind to address
- Failed to bind to addresses
- Failed to parse Endpoint metadata
- Failed to parse Locality Endpoint metadata
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)