diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index 889d71a3084008101d480e7bc983b2c41842ab47..9bf66f347ac17f68cee332a816e30201f7ebc45e 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -37,6 +37,22 @@
 #import <RxLibrary/GRXWriteable.h>
 #import <RxLibrary/GRXWriter+Transformations.h>
 
+static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) {
+  NSDictionary *info = @{
+                         NSLocalizedDescriptionKey: @"Unable to parse response from the server",
+                         NSLocalizedRecoverySuggestionErrorKey: @"If this RPC is idempotent, retry "
+                         @"with exponential backoff. Otherwise, query the server status before "
+                         @"retrying.",
+                         NSUnderlyingErrorKey: parsingError,
+                         @"Expected class": expectedClass,
+                         @"Received value": proto,
+                         };
+  // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public.
+  return [NSError errorWithDomain:@"io.grpc"
+                             code:13
+                         userInfo:info];
+}
+
 @implementation ProtoRPC {
   id<GRXWriteable> _responseWriteable;
 }
@@ -65,14 +81,25 @@
   }
   // A writer that serializes the proto messages to send.
   GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) {
-    // TODO(jcanizales): Fail with an understandable error message if the requestsWriter isn't
-    // sending GPBMessages.
+    if (![proto isKindOfClass:GPBMessage.class]) {
+      [NSException raise:NSInvalidArgumentException
+                  format:@"Request must be a proto message: %@", proto];
+    }
     return [proto data];
   }];
   if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) {
+    __weak ProtoRPC *weakSelf = self;
+
     // A writeable that parses the proto messages received.
     _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
-      [responsesWriteable writeValue:[responseClass parseFromData:value error:NULL]];
+      // TODO(jcanizales): This is done in the main thread, and needs to happen in another thread.
+      NSError *error = nil;
+      id parsed = [responseClass parseFromData:value error:&error];
+      if (parsed) {
+        [responsesWriteable writeValue:parsed];
+      } else {
+        [weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)];
+      }
     } completionHandler:^(NSError *errorOrNil) {
       [responsesWriteable writesFinishedWithError:errorOrNil];
     }];