EpicGames/lore · error · anyhow::Error

Failed to start HTTP server

Error message

Failed to start HTTP server: {err}

What it means

serve (the main Lore HTTP server) parses settings.host:settings.port into a SocketAddr; invalid values are wrapped as "Failed to start HTTP server". The main API server never starts when the address is unparseable.

Solutions

  1. Set host to an IP literal such as 0.0.0.0 and port to a numeric value 0–65535.
  2. Validate the env/config values feeding ServerSettings before launch.
  3. Resolve hostnames to IPs ahead of time; SocketAddr::from_str does not perform DNS lookups.
  4. Wrap IPv6 addresses in brackets in surrounding tooling if they appear in URLs (not needed for the IP field itself).

Example fix

// before
host = "lore.example.com"
port = "https"
// after
host = "0.0.0.0"
port = 8080
Defensive patterns

Strategy: validation

Validate before calling

format!("{}:{}", settings.host, settings.port)
    .parse::<std::net::SocketAddr>()
    .map_err(|e| format!("invalid server addr: {e}"))?;

Try / catch

if let Err(e) = server.serve(...).await {
    if e.to_string().contains("Failed to start HTTP server") {
        eprintln!("check host/port in ServerSettings: {e}");
        std::process::exit(1);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: ServerSettings.host is not a parseable IP literal (DNS hostname, empty string) or settings.port is out of range/non-numeric when calling serve.

Common situations: Deployments set host to a DNS name; port configured via env var with garbage or a service name; empty host after templating failed; IPv6 literal missing brackets.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at lore-server/src/http/server.rs:282

            axum::serve(listener, app)
                .with_graceful_shutdown(signal)
                .await
        })
        .await??;

        Ok(())
    }

    pub async fn serve(
        settings: LoreHttpServerSettings,
        immutable_store: Arc<dyn lore_storage::ImmutableStore>,
        mutable_store: Arc<dyn lore_storage::MutableStore>,
        jwt_verifier: Option<JwtVerifier>,
        repository_authorizer: Arc<dyn RepositoryAuthorizer>,
        signal: impl Future<Output = ()> + Send + 'static,
    ) -> Result<()> {
        let addr = SocketAddr::from_str(format!("{}:{}", settings.host, settings.port).as_str())
            .map_err(|err| anyhow!("Failed to start HTTP server: {err}"))?;
        info!(
            "Starting Lore HTTP Server: {}, Auth: {}",
            &addr,
            jwt_verifier.as_ref().map_or("no", |_| "yes")
        );

        let health = ServerHealth {
            immutable_store: Arc::downgrade(&immutable_store),
            available: AtomicBool::new(true),
            interval_timeout: if settings.available_interval_seconds > 0
                && settings.available_timeout_seconds > 0
            {
                Some((
                    Duration::from_secs(settings.available_interval_seconds),
                    Duration::from_secs(settings.available_timeout_seconds),
                ))
            } else {
                None

View on GitHub (pinned to 074eb0b0d1)