grpc/grpc-java · error · UnsupportedOperationException

Can't unmarshall a parcelable from a regular byte stream

Error message

Can't unmarshall a parcelable from a regular byte stream

What it means

The Parcelable marshaller can only deserialize values that were round-tripped through Android Parcel-backed streams (ParcelableInputStream), which carry the raw Parcelable object. parseStream called on a plain InputStream has no way to recover the Parcelable from raw bytes, so it throws UnsupportedOperationException.

Solutions

  1. Ensure the marshaller's parseStream is only invoked with the ParcelableInputStream produced by the binder transport; do not wrap or copy that stream beforehand.
  2. If the payload may come from a non-Parcel source, use a byte[]/proto-based marshaller for that path instead of the Parcelable marshaller.
  3. In code that accepts an InputStream, check `instanceof ParcelableInputStream` and route plain streams to a different deserializer before calling parseStream.

Example fix

// before
P value = marshaller.parseStream(inputStream);
// after
if (!(inputStream instanceof ParcelableInputStream)) {
  throw new IllegalArgumentException("Parcelable marshaller requires a ParcelableInputStream");
}
P value = marshaller.parseStream(inputStream);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(stream instanceof ParcelableInputStream)) {
  throw new IllegalArgumentException("Parcelable marshaller requires ParcelableInputStream");
}

Type guard

boolean isParcelableStream(InputStream s) { return s instanceof ParcelableInputStream; }

Try / catch

try {
  P p = marshaller.parseStream(stream);
} catch (UnsupportedOperationException e) {
  // route to byte-stream marshaller
}

Prevention

When it happens

Trigger: Calling parseStream() of the Parcelable marshaller with any InputStream that is not a ParcelableInputStream - e.g. feeding it bytes read over the network, a file, or a BufferedInputStream wrapper instead of the original parcel-backed stream.

Common situations: Bridging gRPC messages into non-binder transports; wrapping the transport stream in buffering/decoding streams that lose the ParcelableInputStream type; unit tests that substitute ByteArrayInputStream for the Android stream.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at binder/src/main/java/io/grpc/binder/internal/MetadataHelper.java:223

    public ParcelableMetadataMarshaller(
        @Nullable Parcelable.Creator<P> creator, boolean immutableType) {
      this.creator = creator;
      this.immutableType = immutableType;
    }

    @Override
    public InputStream toStream(P value) {
      return new ParcelableInputStream<>(creator, value, immutableType);
    }

    @Override
    @SuppressWarnings("unchecked")
    public P parseStream(InputStream stream) {
      if (stream instanceof ParcelableInputStream) {
        return ((ParcelableInputStream<P>) stream).getParcelable();
      } else {
        throw new UnsupportedOperationException(
            "Can't unmarshall a parcelable from a regular byte stream");
      }
    }
  }
}

View on GitHub (pinned to 64daddc1f3)