{"id":"a95da77278d269ff","repo":"hyperium/hyper","slug":"invalid-http-version-parsed-found-http2-preface","errorCode":null,"errorMessage":"invalid HTTP version parsed (found HTTP2 preface)","messagePattern":"invalid HTTP version parsed \\(found HTTP2 preface\\)","errorType":"exception","errorClass":"hyper::Error","httpStatus":null,"severity":"error","filePath":"src/error.rs","lineNumber":377,"sourceCode":"    }\n\n    pub(super) fn new_canceled() -> Error {\n        Error::new(Kind::Canceled)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_incomplete() -> Error {\n        Error::new(Kind::IncompleteMessage)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_too_large() -> Error {\n        Error::new(Kind::Parse(Parse::TooLarge))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_version_h2() -> Error {\n        Error::new(Kind::Parse(Parse::VersionH2))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_unexpected_message() -> Error {\n        Error::new(Kind::UnexpectedMessage)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_io(cause: std::io::Error) -> Error {\n        Error::new(Kind::Io).with(cause)\n    }\n\n    #[cfg(any(\n        all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n        all(feature = \"http2\", feature = \"client\")","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/error.rs#L359-L395","documentation":"Thrown via Error::new_version_h2() (src/error.rs:377, Kind::Parse(Parse::VersionH2)), HTTP/1-only feature. It is produced in Conn::on_parse_error (proto/h1/conn.rs:821) specifically when the connection's read buffer starts with the HTTP/2 connection preface (H2_PREFACE = b\"PRI * HTTP/2.0\\r\\n\\r\\nSM\\r\\n\\r\\n\", conn.rs:29, detected by has_h2_prefix at conn.rs:206). It means the peer spoke HTTP/2 to a listener configured for HTTP/1 only. Detect with Error::is_parse_version_h2().","triggerScenarios":"An HTTP/2 client connects to a plain HTTP/1 server (no TLS ALPN, no h2 in the server Builder); a service built with Http::new() (http1 only) receives the PRI/SM preface; ALPN negotiated h2 but the server was only built for http1. The 24-byte preface is matched in conn.rs:208.","commonSituations":"Mixing up http1/http2 feature flags in Cargo (server built without the http2 feature, or only http1 enabled); a client hard-coded to h2 hitting an http1 endpoint; a reverse proxy upstreaming h2 to an h1 backend; misconfigured ALPN where the listener speaks h1 but the client chose h2.","solutions":["Enable HTTP/2 on the listener (enable the http2 feature and build the server with the h2 handshake) so the preface is handled instead of rejected.","If you only support HTTP/1, configure the client to use HTTP/1 (e.g. http2_only(false) / http1_only) so it never sends the preface.","For TLS, set ALPN correctly (e.g. [\"h2\", \"http/1.1\"]) so negotiation lands on a mutually supported protocol."],"exampleFix":"// before: server only speaks HTTP/1, rejects HTTP/2 clients\nlet mut http = hyper::server::conn::Http::new(); // http1 only\n\n// after: enable HTTP/2 so the preface is accepted\n// (requires the \"http2\" cargo feature)\nlet make_svc = hyper::server::conn::auto::Builder::new(tokio_io)\n    .serve_connection(stream, svc);","handlingStrategy":"validation","validationCode":"// Decide protocol up front and build the matching server/client.\n// For TLS, configure ALPN so negotiation is authoritative:\nlet alpn = tokio_rustls::rustls::ServerConfig::builder()\n    .with_no_client_auth()\n    .with_protocols(&[b\"h2\" as &[u8], b\"http/1.1\"])\n    .into();","typeGuard":"fn is_h2_preface_on_h1(err: &hyper::Error) -> bool {\n    err.is_parse_version_h2()\n}","tryCatchPattern":"match serve_connection(...).await {\n    Err(e) if e.is_parse_version_h2() => {\n        // peer needs h2; rebuild this listener with the http2 feature / auto Builder\n    }\n    other => other,\n}","preventionTips":["Enable the http2 cargo feature on both peers that must speak h2.","Use server::conn::auto::Builder when a listener must accept both h1 and h2.","Set ALPN correctly on TLS so the client and server agree on protocol before bytes flow."],"tags":["http1","http2","alpn","protocol-mismatch","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}