EpicGames/lore · error · anyhow::Error

Stream handler factory was not set

Error message

Stream handler factory was not set

What it means

The QuinnConfig builder requires a stream handler factory before build(); it is what decides which ALPN protocols and services the QUIC server can dispatch to. If the builder was never given one via the builder method, build() returns this error rather than constructing a useless server.

Solutions

  1. Call the stream_handler_factory setter with a configured factory before build()
  2. Check launch_quinn_server to confirm every builder field is set
  3. Add a builder-level debug assert or default factory to catch this at compile/early time

Example fix

// before
let cfg = QuinnConfigBuilder::new().address(addr).build()?;
// after
let cfg = QuinnConfigBuilder::new().address(addr).stream_handler_factory(factory).build()?;
Defensive patterns

Strategy: validation

Validate before calling

let cfg = QuinnConfigBuilder::new();
// ensure factory is set before build
assert!(builder_has_stream_handler(&cfg), "stream_handler_factory must be set");
let quinn_cfg = cfg.build()?;

Try / catch

match cfg.build() {
    Err(e) if e.to_string().contains("Stream handler factory") => panic!("builder misuse: set stream_handler_factory before build"),
    r => r?,
}

Prevention

When it happens

Trigger: Calling QuinnConfigBuilder::build() without first calling the stream_handler_factory setter; typically a coding mistake in launch_quinn_server wiring or a refactor that dropped the setter call.

Common situations: Refactoring server launch code and forgetting the builder step; conditionally skipping handler registration; copying builder code and omitting a line.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

    pub fn metrics_frequency(mut self, metric_frequency: Duration) -> Self {
        self.metrics_frequency = Some(metric_frequency);
        self
    }

    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,

View on GitHub (pinned to 074eb0b0d1)