neondatabase/neon · error

invalid protocol scheme: {scheme}

Error message

invalid protocol scheme: {scheme}

What it means

Thrown by PageserverProtocol::from_connstring() in neon's compute_api when the connstring parsed successfully as a URL but its scheme is neither postgresql/postgres (Libpq) nor grpc (Grpc). The scheme comparison is done on the lowercased scheme, so only these three spellings are accepted; everything else is rejected as an unsupported protocol.

Source

Thrown at libs/compute_api/src/spec.rs:653

    Libpq,
    /// A newer, gRPC-based protocol. Uses grpc:// scheme.
    #[serde(rename = "grpc")]
    Grpc,
}

impl PageserverProtocol {
    /// Parses the protocol from a connstring scheme. Defaults to Libpq if no scheme is given.
    /// Errors if the connstring is an invalid URL.
    pub fn from_connstring(connstring: &str) -> anyhow::Result<Self> {
        let scheme = match Url::parse(connstring) {
            Ok(url) => url.scheme().to_lowercase(),
            Err(url::ParseError::RelativeUrlWithoutBase) => return Ok(Self::default()),
            Err(err) => return Err(anyhow!("invalid connstring URL: {err}")),
        };
        match scheme.as_str() {
            "postgresql" | "postgres" => Ok(Self::Libpq),
            "grpc" => Ok(Self::Grpc),
            scheme => Err(anyhow!("invalid protocol scheme: {scheme}")),
        }
    }

    /// Returns the URL scheme for the protocol, for use in connstrings.
    pub fn scheme(&self) -> &'static str {
        match self {
            Self::Libpq => "postgresql",
            Self::Grpc => "grpc",
        }
    }
}

impl Display for PageserverProtocol {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.scheme())
    }
}

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Check the scheme of the connstring and change it to postgresql://, postgres://, or grpc:// as appropriate
  2. Make sure you passed the data-plane connstring, not the pageserver HTTP management URL
  3. Fix typos in the scheme (it must be exactly postgres, postgresql, or grpc, case-insensitive)
  4. If the string has no scheme at all, that is fine — from_connstring defaults to Libpq; only wrong schemes fail

Example fix

# before
PAGESERVER_CONNSTRING="http://pageserver-0:9898"   # invalid protocol scheme: http

# after
PAGESERVER_CONNSTRING="postgres://pageserver-0:6400" # or grpc://pageserver-0:50051
Defensive patterns

Strategy: validation

Validate before calling

// Accept only the three supported schemes before use:
fn scheme_supported(s: &str) -> bool {
    url::Url::parse(s).ok()
        .map(|u| matches!(u.scheme().to_lowercase().as_str(), "postgres" | "postgresql" | "grpc"))
        .unwrap_or(true) // scheme-less defaults to Libpq
}

Try / catch

// Distinguish scheme errors from malformed-URL errors for clearer operator messages:
match PageserverProtocol::from_connstring(s) {
    Ok(p) => Ok(p),
    Err(e) if e.to_string().contains("invalid protocol scheme") => {
        Err(anyhow!("{s}: use postgresql:// or grpc://; HTTP management URLs are not valid here"))
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: from_connstring("http://pageserver:6400") or from_connstring("ws://host") — any URL with a scheme other than postgres, postgresql, or grpc, e.g. an accidentally supplied management-HTTP URL where a data-plane connstring was expected.

Common situations: Pasting the pageserver's HTTP management endpoint (http://...:9898) into a field that expects the postgres or grpc data-plane connstring; a wrapper tool that prefixes ws:// or tcp:// to every address; typos like postgress:// or grcp://.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/a63245a37a0324e3. Report an issue: GitHub.