{"record":{"id":"3f41226ef0ec05a5","repo":"EpicGames/lore","slug":"stream-handler-factory-was-not-set","errorCode":null,"errorMessage":"Stream handler factory was not set","messagePattern":"Stream handler factory was not set","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"lore-server/src/quic/quinn/config.rs","lineNumber":191,"sourceCode":"    pub fn metrics_frequency(mut self, metric_frequency: Duration) -> Self {\n        self.metrics_frequency = Some(metric_frequency);\n        self\n    }\n\n    pub fn transport_bits_per_second(mut self, bits_per_second: usize) -> Self {\n        self.transport_bits_per_second = Some(bits_per_second);\n        self\n    }\n\n    pub fn transport_rtt(mut self, rtt: usize) -> Self {\n        self.transport_rtt = Some(rtt);\n        self\n    }\n\n    pub fn build(self) -> anyhow::Result<QuinnConfig> {\n        let stream_handler_factory = self\n            .stream_handler_factory\n            .ok_or(anyhow!(\"Stream handler factory was not set\"))?;\n\n        let alpns = stream_handler_factory.supported_protocols();\n        if alpns.is_empty() {\n            return Err(anyhow!(\"No alpns provided\"));\n        };\n\n        // A caller-bound socket is the truth about where this serves; asking it beats trusting an\n        // `address` set alongside it, which could disagree.\n        let address = match &self.socket {\n            Some(socket) => socket.local_addr()?,\n            None => self.address.ok_or(anyhow!(\"Address was not set\"))?,\n        };\n\n        Ok(QuinnConfig {\n            server_metrics_name: self.server_metrics_name,\n            address,\n            socket: self.socket,\n            alpns,","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/quic/quinn/config.rs#L173-L209","documentation":"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.","triggerScenarios":"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.","commonSituations":"Refactoring server launch code and forgetting the builder step; conditionally skipping handler registration; copying builder code and omitting a line.","solutions":["Call the stream_handler_factory setter with a configured factory before build()","Check launch_quinn_server to confirm every builder field is set","Add a builder-level debug assert or default factory to catch this at compile/early time"],"exampleFix":"// before\nlet cfg = QuinnConfigBuilder::new().address(addr).build()?;\n// after\nlet cfg = QuinnConfigBuilder::new().address(addr).stream_handler_factory(factory).build()?;","handlingStrategy":"validation","validationCode":"let cfg = QuinnConfigBuilder::new();\n// ensure factory is set before build\nassert!(builder_has_stream_handler(&cfg), \"stream_handler_factory must be set\");\nlet quinn_cfg = cfg.build()?;","typeGuard":null,"tryCatchPattern":"match cfg.build() {\n    Err(e) if e.to_string().contains(\"Stream handler factory\") => panic!(\"builder misuse: set stream_handler_factory before build\"),\n    r => r?,\n}","preventionTips":["Wrap builder construction in a helper function that always sets the factory","Use typestate builder APIs where available to make unset fields unbuildable"],"tags":["rust","quic","builder-pattern"],"backgroundTag":"missing-required-option","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}