EpicGames/lore · error · anyhow::Error

No alpns provided

Error message

No alpns provided

What it means

A generic validation guard in QuinnConfig::build: the assembled stream handler factory advertises no supported ALPN protocols, so the QUIC server would have nothing to negotiate with clients. It fires when launch_quinn_server builds the config before any protocols have been registered on the factory, meaning server startup configuration is incomplete rather than a runtime connection failure.

Solutions

  1. Register at least one stream handler/protocol in the factory before building the config
  2. Check whether feature flags or empty service lists left the factory with no registrations
  3. Log factory registrations at startup to verify non-empty ALPNs

Example fix

// before
let factory = StreamHandlerFactory::new(); // no handlers registered
// after
let factory = StreamHandlerFactory::new().register("lore/1", handler);
Defensive patterns

Strategy: validation

Validate before calling

if factory.supported_protocols().is_empty() {
    return Err("stream handler factory has no registered protocols; register at least one before launch".into());
}

Type guard

fn has_protocols(f: &dyn StreamHandlerFactory) -> bool {
    !f.supported_protocols().is_empty()
}

Try / catch

match cfg.build() {
    Err(e) if e.to_string().contains("No alpns") => eprintln!("register handlers before building QUIC config"),
    r => r?,
}

Prevention

When it happens

Trigger: build() is called and stream_handler_factory.supported_protocols() returns an empty slice — i.e., a factory that was constructed with no services/protocols registered.

Common situations: Constructing a default/empty factory in tests; a registration loop that iterates an empty service list; feature flags disabling all services so nothing registers.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/fd469d4449e5468c. Report an issue: GitHub.

Appendix: source

Thrown at lore-server/src/quic/quinn/config.rs:195

    pub fn transport_bits_per_second(mut self, bits_per_second: usize) -> Self {
        self.transport_bits_per_second = Some(bits_per_second);
        self
    }

    pub fn transport_rtt(mut self, rtt: usize) -> Self {
        self.transport_rtt = Some(rtt);
        self
    }

    pub fn build(self) -> anyhow::Result<QuinnConfig> {
        let stream_handler_factory = self
            .stream_handler_factory
            .ok_or(anyhow!("Stream handler factory was not set"))?;

        let alpns = stream_handler_factory.supported_protocols();
        if alpns.is_empty() {
            return Err(anyhow!("No alpns provided"));
        };

        // A caller-bound socket is the truth about where this serves; asking it beats trusting an
        // `address` set alongside it, which could disagree.
        let address = match &self.socket {
            Some(socket) => socket.local_addr()?,
            None => self.address.ok_or(anyhow!("Address was not set"))?,
        };

        Ok(QuinnConfig {
            server_metrics_name: self.server_metrics_name,
            address,
            socket: self.socket,
            alpns,
            cert_file: self.cert_file,
            pkey_file: self.pkey_file,
            cert_chain: self.cert_chain,
            client_cert_verifier: self

View on GitHub (pinned to 074eb0b0d1)