{"record":{"id":"ea7cd7fc69d1c4ec","repo":"netbirdio/netbird","slug":"no-relay-transport-available","errorCode":null,"errorMessage":"no relay transport available","messagePattern":"no relay transport available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/relay/client/dialer/race_dialer.go","lineNumber":177,"sourceCode":"}\n\n// orderedErrs returns the per-protocol errors in dialer order, so the combined\n// error is stable regardless of which attempt failed first.\nfunc (r *RaceDial) orderedErrs(byProtocol map[string]error) []error {\n\terrs := make([]error, 0, len(byProtocol))\n\tfor _, dfn := range r.dialerFns {\n\t\tif err, ok := byProtocol[dfn.Protocol()]; ok {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\treturn errs\n}\n\n// dialErr combines per-dialer failures, preserving the underlying reasons\n// (e.g. \"connection refused\") rather than a generic message.\nfunc dialErr(errs []error) error {\n\tif len(errs) == 0 {\n\t\treturn errors.New(\"no relay transport available\")\n\t}\n\treturn errors.Join(errs...)\n}\n","sourceCodeStart":159,"sourceCodeEnd":181,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/shared/relay/client/dialer/race_dialer.go#L159-L181","documentation":"dialErr combines per-dialer failures, and returns this error only when the collected error list is empty — meaning no registered transport dialer reported any result for the requested protocol. This is distinct from dialers that ran and failed (those errors would be joined): here the race dialer had no transport available to attempt at all.","triggerScenarios":"All transport dialers (e.g. QUIC/TCP) disabled by build tags, configuration, or platform constraints, so none attempts the relay connection.","commonSituations":"A binary built without a transport dependency; transports disabled via config or env; running on a platform where the only compiled transport is unavailable.","solutions":["Enable the default relay transports in the client configuration","Rebuild without excluding transport build tags","Upgrade the relay client so at least one transport is registered"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"supported := dialer.SupportedProtocols() // e.g. from your dialer registry\nif len(supported) == 0 {\n\treturn fmt.Errorf(\"no relay transport compiled in; rebuild with default transports\")\n}","typeGuard":null,"tryCatchPattern":"conn, err := raceDialer.Dial(ctx, addr)\nif err != nil {\n\tif err.Error() == \"no relay transport available\" {\n\t\t// configuration/build defect, not a network failure: fall back to a default transport-enabled client\n\t}\n\treturn nil, err\n}","preventionTips":["Assert at startup that at least one transport dialer is registered","Do not disable transports via build tags unless another is guaranteed","Distinguish 'no transport' from 'transport failed' in error handling"],"tags":["relay","transport","dialer","configuration"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}