diff --git a/rpc_util.go b/rpc_util.go
index 96c790be..df3486bc 100644
--- a/rpc_util.go
+++ b/rpc_util.go
@@ -325,7 +325,7 @@ type rpcError struct {
 }
 
 func (e rpcError) Error() string {
-	return fmt.Sprintf("rpc error: code = %d desc = %q", e.code, e.desc)
+	return fmt.Sprintf("rpc error: code = %d desc = %s", e.code, e.desc)
 }
 
 // Code returns the error code for err if it was produced by the rpc system.
diff --git a/transport/http2_client.go b/transport/http2_client.go
index 986eb1de..c9c8910b 100644
--- a/transport/http2_client.go
+++ b/transport/http2_client.go
@@ -721,14 +721,14 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
 	s.write(recvMsg{err: io.EOF})
 }
 
-func handleMalformedHTTP2(s *Stream, err http2.StreamError) {
+func handleMalformedHTTP2(s *Stream, err error) {
 	s.mu.Lock()
 	if !s.headerDone {
 		close(s.headerChan)
 		s.headerDone = true
 	}
 	s.mu.Unlock()
-	s.write(recvMsg{err: StreamErrorf(http2ErrConvTab[err.Code], "%v", err)})
+	s.write(recvMsg{err: err})
 }
 
 // reader runs as a separate goroutine in charge of reading data from network
@@ -763,7 +763,8 @@ func (t *http2Client) reader() {
 				s := t.activeStreams[se.StreamID]
 				t.mu.Unlock()
 				if s != nil {
-					handleMalformedHTTP2(s, se)
+					// use error detail to provide better err message
+					handleMalformedHTTP2(s, StreamErrorf(http2ErrConvTab[se.Code], "%v", t.framer.errorDetail()))
 				}
 				continue
 			} else {
diff --git a/transport/http_util.go b/transport/http_util.go
index 6aabcd4a..73c12d5f 100644
--- a/transport/http_util.go
+++ b/transport/http_util.go
@@ -404,3 +404,7 @@ func (f *framer) flushWrite() error {
 func (f *framer) readFrame() (http2.Frame, error) {
 	return f.fr.ReadFrame()
 }
+
+func (f *framer) errorDetail() error {
+	return f.fr.ErrorDetail()
+}
diff --git a/transport/transport_test.go b/transport/transport_test.go
index a05b3ac8..c9a95328 100644
--- a/transport/transport_test.go
+++ b/transport/transport_test.go
@@ -681,7 +681,7 @@ func TestMalformedStatus(t *testing.T) {
 		t.Fatalf("Failed to write the request: %v", err)
 	}
 	p := make([]byte, http2MaxFrameLen)
-	expectedErr := StreamErrorf(codes.Internal, "stream error: stream ID 1; PROTOCOL_ERROR")
+	expectedErr := StreamErrorf(codes.Internal, "invalid header field value \"\\n\"")
 	if _, err = s.dec.Read(p); err != expectedErr {
 		t.Fatalf("Read the err %v, want %v", err, expectedErr)
 	}