diff --git a/src/error.rs b/src/error.rs
index b07a22c409..92806cef3d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -61,7 +61,7 @@ pub(super) enum Parse {
     Version,
     #[cfg(feature = "http1")]
     VersionH2,
-    Uri,
+    Uri(InvalidUri),
     #[cfg_attr(not(all(feature = "http1", feature = "server")), allow(unused))]
     UriTooLong,
     Header(Header),
@@ -123,6 +123,12 @@ pub(super) enum User {
 #[derive(Debug)]
 pub(super) struct TimedOut;
 
+pub(super) enum InvalidUri {
+    Uri(http::uri::InvalidUri),
+    Parts(http::uri::InvalidUriParts),
+    Other(&'static str),
+}
+
 impl Error {
     /// Returns true if this was an HTTP parse error.
     pub fn is_parse(&self) -> bool {
@@ -343,7 +349,7 @@ impl Error {
             Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
             #[cfg(feature = "http1")]
             Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
-            Kind::Parse(Parse::Uri) => "invalid URI",
+            Kind::Parse(Parse::Uri(_)) => "invalid URI",
             Kind::Parse(Parse::UriTooLong) => "URI too long",
             Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed",
             #[cfg(feature = "http1")]
@@ -420,6 +426,11 @@ impl fmt::Debug for Error {
 
 impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // handle "invalid URI" parse errors separately, since the inner error
+        // is not stored as a cause.
+        if let Kind::Parse(Parse::Uri(ref error)) = self.inner.kind {
+            return fmt::Display::fmt(error, f);
+        }
         if let Some(ref cause) = self.inner.cause {
             write!(f, "{}: {}", self.description(), cause)
         } else {
@@ -487,14 +498,14 @@ impl From<http::status::InvalidStatusCode> for Parse {
 }
 
 impl From<http::uri::InvalidUri> for Parse {
-    fn from(_: http::uri::InvalidUri) -> Parse {
-        Parse::Uri
+    fn from(inner: http::uri::InvalidUri) -> Parse {
+        Parse::Uri(InvalidUri::Uri(inner))
     }
 }
 
 impl From<http::uri::InvalidUriParts> for Parse {
-    fn from(_: http::uri::InvalidUriParts) -> Parse {
-        Parse::Uri
+    fn from(inner: http::uri::InvalidUriParts) -> Parse {
+        Parse::Uri(InvalidUri::Parts(inner))
     }
 }
 
@@ -513,6 +524,28 @@ impl fmt::Display for TimedOut {
 
 impl StdError for TimedOut {}
 
+// === impl InvalidUri ===
+
+impl fmt::Display for InvalidUri {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Other(msg) => write!(f, "invalid URI: {}", msg),
+            Self::Uri(e) => fmt::Display::fmt(e, f),
+            Self::Parts(e) => fmt::Display::fmt(e, f),
+        }
+    }
+}
+
+impl fmt::Debug for InvalidUri {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Other(msg) => f.debug_tuple("InvalidUri").field(msg).finish(),
+            Self::Uri(e) => fmt::Debug::fmt(e, f),
+            Self::Parts(e) => fmt::Debug::fmt(e, f),
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs
index d28c44889c..549eaa75a8 100644
--- a/src/proto/h1/role.rs
+++ b/src/proto/h1/role.rs
@@ -182,7 +182,7 @@ impl Http1Transaction for Server {
                                 Parse::Method
                             } else {
                                 debug_assert!(req.path.is_none());
-                                Parse::Uri
+                                Parse::Uri(error::InvalidUri::Other("invalid token"))
                             }
                         }
                         other => other.into(),
@@ -445,7 +445,7 @@ impl Http1Transaction for Server {
         let status = match *err.kind() {
             Kind::Parse(Parse::Method)
             | Kind::Parse(Parse::Header(_))
-            | Kind::Parse(Parse::Uri)
+            | Kind::Parse(Parse::Uri(_))
             | Kind::Parse(Parse::Version) => StatusCode::BAD_REQUEST,
             Kind::Parse(Parse::TooLarge) => StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
             Kind::Parse(Parse::UriTooLong) => StatusCode::URI_TOO_LONG,