caddyserver/caddy · error

network '%s' cannot handle HTTP/1 or HTTP/2 connections

Error message

network '%s' cannot handle HTTP/1 or HTTP/2 connections

What it means

After successfully creating a socket for an HTTP-capable protocol set, Caddy asserts the returned object is a net.Listener (stream socket). Non-stream networks (e.g. unixgram, or packet-oriented networks) cannot serve HTTP/1 or HTTP/2, so Start rejects them with the network name from the listen address.

Source

Thrown at modules/caddyhttp/app.go:574

				// enable TLS if there is a policy and if this is not the HTTP port
				useTLS := len(srv.TLSConnPolicies) > 0 && int(listenAddr.StartPort+portOffset) != app.httpPort()

				if h1ok || h2ok && useTLS || h2cok {
					// create the listener for this socket
					lnAny, err := listenAddr.Listen(app.ctx, portOffset, net.ListenConfig{
						KeepAliveConfig: net.KeepAliveConfig{
							Enable:   srv.KeepAliveInterval >= 0,
							Interval: time.Duration(srv.KeepAliveInterval),
							Idle:     time.Duration(srv.KeepAliveIdle),
							Count:    srv.KeepAliveCount,
						},
					})
					if err != nil {
						return fmt.Errorf("listening on %s: %v", listenAddr.At(portOffset), err)
					}
					ln, ok := lnAny.(net.Listener)
					if !ok {
						return fmt.Errorf("network '%s' cannot handle HTTP/1 or HTTP/2 connections", listenAddr.Network)
					}

					// wrap listener before TLS (up to the TLS placeholder wrapper)
					var lnWrapperIdx int
					for i, lnWrapper := range srv.listenerWrappers {
						if _, ok := lnWrapper.(*tlsPlaceholderWrapper); ok {
							lnWrapperIdx = i + 1 // mark the next wrapper's spot
							break
						}
						ln = lnWrapper.WrapListener(ln)
					}

					if useTLS {
						// create TLS listener - this enables and terminates TLS
						ln = tls.NewListener(ln, tlsCfg)
					}

					// finish wrapping listener where we left off before TLS

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Use a stream network for HTTP servers: plain host:port (tcp) or unix/<path> ("unix//tmp/caddy.sock")
  2. Reserve udp/GRAM networks for the automatic HTTP/3 handling, not explicit listen entries

Example fix

// before
"listen": ["unixgram//run/caddy.sock"]
// after
"listen": ["unix//run/caddy.sock"]
Defensive patterns

Strategy: validation

Validate before calling

for _, a := range srvCfg.Listen {
    na, err := caddy.ParseNetworkAddress(a)
    if err != nil { return err }
    switch na.Network {
    case "", "tcp", "tcp4", "tcp6", "unix":
    default:
        if !strings.Contains(na.Network, "gram") && na.Network != "udp" { /* ... */ }
        return fmt.Errorf("network %q cannot serve HTTP/1-2; use tcp/unix", na.Network)
    }
}

Prevention

When it happens

Trigger: Using a datagram/packet network in listen for a server whose protocols include h1/h2/h2c, e.g. "unixgram//path/to/socket" or ip4 networks; only quic-capable networks legitimately use packet conns via the HTTP/3 path.

Common situations: Trying to serve HTTP over a unixgram socket copied from a UDP example; mistaking the l4 module's network syntax for http server listen syntax.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/6456940b9bd1cd21. Report an issue: GitHub.