cloudflare/cloudflared · error

invalid protocol selected: %s

Error message

invalid protocol selected: %s

What it means

serveConnection switches on the negotiated transport protocol (QUIC, HTTP2, ...). If the protocol value is anything else — a corrupted config, an unknown future enum, or a programmer error — the default branch rejects it as 'invalid protocol selected: %s' as unrecoverable, since retrying with the same invalid protocol cannot succeed.

Source

Thrown at supervisor/tunnel.go:499

		// Rebuild the connection options with the local address now that the
		// edge socket is established.
		// nolint: gosec
		connOptions := e.config.connectionOptions(edgeConn.LocalAddr().String(), uint8(backoff.Retries()))
		// nolint: zerologlint
		connOptions.LogFields(connLog.Logger().Debug().Uint8(connection.LogFieldConnIndex, connIndex)).Msgf("Tunnel connection options")
		if err := e.serveHTTP2(
			ctx,
			connLog,
			edgeConn,
			connOptions,
			controlStream,
			connIndex,
		); err != nil {
			return err, false
		}

	default:
		return fmt.Errorf("invalid protocol selected: %s", protocol), false
	}
	return
}

type unrecoverableError struct {
	err error
}

func (r unrecoverableError) Error() string {
	return r.err.Error()
}

func (e *EdgeTunnelServer) serveHTTP2(
	ctx context.Context,
	connLog *ConnAwareLogger,
	tlsServerConn net.Conn,
	connOptions *client.ConnectionOptionsSnapshot,
	controlStreamHandler connection.ControlStreamHandler,

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Check the --protocol flag and config file: valid values are quic, http2, or auto.
  2. Remove or fix the invalid protocol entry and re-run with `--protocol auto` to let cloudflared negotiate.
  3. Upgrade cloudflared if the edge is assigning a protocol your binary predates.
  4. Validate the tunnel config JSON/YAML for stray or renamed fields under protocol selection.

Example fix

// before
cloudflared tunnel run --protocol h3 my-tunnel
// after
cloudflared tunnel run --protocol auto my-tunnel
Defensive patterns

Strategy: try-catch

Validate before calling

// at startup: verify the base config exists before serving
if e.config.EdgeTLSConfigs[connection.HTTP2] == nil {
	return errors.New("HTTP2 edge TLS config was not initialized")
}

Try / catch

tlsConfig, err := cfdcrypto.TLSConfigWithCurvePreferences(e.config.EdgeTLSConfigs[protocol], pqMode)
if err != nil {
	log.Error().Err(err).Msg("TLS config build failed; will retry")
	return fmt.Errorf("could not create TLS configuration: %w", err), true
}

Prevention

When it happens

Trigger: The resolved protocol from config/CLI (--protocol) or edge negotiation holds a value outside the known set (e.g. hand-edited config file with `protocol: tcp`, stale flag parsing, or a binary older than a newly introduced protocol returned by remote config).

Common situations: Typoed --protocol flag value; stale/foreign config file entries under tunnel credentials/remote configuration; mixed-version environments where edge assigns a protocol this binary does not know.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/68401507a8a2e624. Report an issue: GitHub.