{"record":{"id":"c805a38f95e0f2bb","repo":"kubernetes/kops","slug":"error-querying-kubernetes-version-v","errorCode":null,"errorMessage":"error querying kubernetes version: %v","messagePattern":"error querying kubernetes version: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/pkg/cmd/apply_channel.go","lineNumber":190,"sourceCode":"\n\tcmClient, err := certmanager.NewForConfigAndClient(restConfig, httpClient)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"building cert manager client: %w\", err)\n\t}\n\n\tdynamicClient, err := f.DynamicClient()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"building dynamic client: %w\", err)\n\t}\n\n\trestMapper, err := f.RESTMapper()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tkubernetesVersionInfo, err := k8sClient.Discovery().ServerVersion()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error querying kubernetes version: %v\", err)\n\t}\n\n\tkubernetesVersion, err := semver.ParseTolerant(kubernetesVersionInfo.GitVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot parse kubernetes version %q\", kubernetesVersionInfo.GitVersion)\n\t}\n\n\t// Remove Pre and Patch, as they make semver comparisons impractical\n\tkubernetesVersion.Pre = nil\n\n\tif len(args) == 0 {\n\t\treturn fmt.Errorf(\"at least one channel URL is required\")\n\t}\n\n\tvar merr error\n\tfor _, channelLocation := range args {\n\t\tmenu, err := buildMenu(f.VFSContext(), kubernetesVersion, channelLocation)\n\t\tif err != nil {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/channels/pkg/cmd/apply_channel.go#L172-L208","documentation":"RunApplyChannel queries the cluster's server version via k8sClient.Discovery().ServerVersion() to gate channel addon versions. If the discovery request fails (unreachable apiserver, auth error, TLS error), it wraps the cause with this message and aborts the apply. Unlike some other paths it uses %v, so the inner error is not unwrap-able via errors.As/Is.","triggerScenarios":"`kops channels apply` against a cluster whose apiserver is down or unreachable; wrong endpoint/port; expired tokens or certs rejected at discovery time; network partition from the pod to the control plane.","commonSituations":"Running during control-plane bootstrap (normal in daemon mode — the loop retries every 5s); firewall/Security Group blocking 443; DNS not resolving the apiserver name; certificate rotation in progress.","solutions":["Test connectivity: `kubectl --kubeconfig <cfg> version` from the same host/pod","Verify the apiserver endpoint, DNS, and firewall rules (port 443)","Refresh credentials (kops export kubeconfig or rotated service-account tokens)","If in daemon mode during startup, wait — the loop retries automatically"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Go: probe the apiserver before running apply\nclientset, _ := f.KubernetesClient()\nif _, err := clientset.Discovery().ServerVersion(); err != nil {\n\treturn fmt.Errorf(\"precheck: apiserver unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := RunApplyChannel(ctx, f, out, options, args)\nif err != nil && strings.Contains(err.Error(), \"error querying kubernetes version\") {\n\t// note: wrapped with %v, not unwrappable; treat as transient and back off\n\ttime.Sleep(5 * time.Second)\n\treturn retry(ctx)\n}","preventionTips":["Verify DNS/firewall allow egress to the apiserver on 443","Refresh tokens/certs before expiry (kops export kubeconfig)","Rely on the daemon loop's 5s startup retry during control-plane bring-up","Alert on persistent discovery failures rather than crash-looping"],"tags":["kubernetes","network","discovery","apiserver"],"backgroundTag":"apiserver-unreachable","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}