netbirdio/netbird · critical

unexpected config protocol type %v

Error message

unexpected config protocol type %v

What it means

A panic raised by ToResponseProto in management/internals/shared/grpc/conversion.go:277 when the management server's configured signal protocol (nbconfig.Protocol) is not one of the mapped values UDP, DTLS, HTTP, HTTPS, TCP. It exists to catch config/proto drift at runtime; an unmapped value crashes the request path instead of silently sending a wrong protocol to the agent.

Source

Thrown at management/internals/shared/grpc/conversion.go:277

	}

	return precomputedDeprecatedRemotePeersConstraint.Check(peerNBVersion)
}

func ToResponseProto(configProto nbconfig.Protocol) proto.HostConfig_Protocol {
	switch configProto {
	case nbconfig.UDP:
		return proto.HostConfig_UDP
	case nbconfig.DTLS:
		return proto.HostConfig_DTLS
	case nbconfig.HTTP:
		return proto.HostConfig_HTTP
	case nbconfig.HTTPS:
		return proto.HostConfig_HTTPS
	case nbconfig.TCP:
		return proto.HostConfig_TCP
	default:
		panic(fmt.Errorf("unexpected config protocol type %v", configProto))
	}
}

// buildJWTConfig constructs JWT configuration for SSH servers from management server config
func buildJWTConfig(config *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow) *proto.JWTConfig {
	if config == nil || config.AuthAudience == "" {
		return nil
	}

	issuer := strings.TrimSpace(config.AuthIssuer)
	if issuer == "" && deviceFlowConfig != nil {
		if d := deriveIssuerFromTokenEndpoint(deviceFlowConfig.ProviderConfig.TokenEndpoint); d != "" {
			issuer = d
		}
	}
	if issuer == "" {
		return nil
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check which nbconfig.Protocol value reached the switch (the panic message prints it with %v) and add a matching proto.HostConfig_* case or map it deliberately.
  2. Ensure the management signal configuration (signal protocol settings) uses one of the supported values UDP/DTLS/HTTP/HTTPS/TCP.
  3. Redeploy management from a consistent build so config parsing and conversion share the same protocol set.

Example fix

// before
default:
    panic(fmt.Errorf("unexpected config protocol type %v", configProto))

// after: handle the new constant instead of panicking
case nbconfig.QUIC:
    return proto.HostConfig_QUIC
default:
    panic(fmt.Errorf("unexpected config protocol type %v", configProto))
Defensive patterns

Strategy: validation

Validate before calling

// Go: guard config before calling into the conversion path
func isSupportedProtocol(p nbconfig.Protocol) bool {
    switch p {
    case nbconfig.UDP, nbconfig.DTLS, nbconfig.HTTP, nbconfig.HTTPS, nbconfig.TCP:
        return true
    }
    return false
}

if !isSupportedProtocol(cfg.Protocol) {
    return fmt.Errorf("unsupported signal protocol: %v", cfg.Protocol)
}

Try / catch

// Go: keep the panic from killing the whole process at API boundaries
// (the panic is intentional fail-fast; recovery is for supervisors)
defer func() {
    if r := recover(); r != nil {
        log.Errorf("conversion panic: %v", r)
        err = fmt.Errorf("protocol conversion failed")
    }
}()
resp, err = convert(configProto)

Prevention

When it happens

Trigger: Management receives a Sync/Login flow whose host config carries a Protocol value outside the known set — typically a newly introduced nbconfig constant that was never added to this switch, or a hand-edited/back-incompatible management config.

Common situations: Running a management build where nbconfig gained a new protocol constant (version skew between config parsing and this conversion); development branches adding a transport without updating the switch; corrupt or unusual signal configuration data.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/1ae1e27484467045. Report an issue: GitHub.