{"record":{"id":"e056af41a3a9caba","repo":"kubernetes/kops","slug":"challenge-not-set","errorCode":null,"errorMessage":"challenge not set","messagePattern":"challenge not set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/bootstrap/challenge_client.go","lineNumber":71,"sourceCode":"\t}, c.keystore)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating certificate: %w\", err)\n\t}\n\n\t// TODO: Caching and rotation\n\tclientCertificate := &tls.Certificate{\n\t\tPrivateKey:  privateKey.Key,\n\t\tCertificate: [][]byte{certificate.Certificate.Raw},\n\t\tLeaf:        certificate.Certificate,\n\t}\n\treturn clientCertificate, nil\n}\n\nfunc (c *ChallengeClient) DoCallbackChallenge(ctx context.Context, clusterName string, targetEndpoint string, bootstrapRequest *nodeup.BootstrapRequest) error {\n\tchallenge := bootstrapRequest.Challenge\n\n\tif challenge == nil {\n\t\treturn fmt.Errorf(\"challenge not set\")\n\t}\n\tif challenge.ChallengeID == \"\" {\n\t\treturn fmt.Errorf(\"challenge.id not set\")\n\t}\n\tif len(challenge.ChallengeSecret) == 0 {\n\t\treturn fmt.Errorf(\"challenge.secret not set\")\n\t}\n\tif challenge.Endpoint == \"\" {\n\t\treturn fmt.Errorf(\"challenge.endpoint not set\")\n\t}\n\tif len(challenge.ServerCA) == 0 {\n\t\treturn fmt.Errorf(\"challenge.ca not set\")\n\t}\n\n\tclientCertificate, err := c.getClientCertificate(ctx, clusterName)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/bootstrap/challenge_client.go#L53-L89","documentation":"DoCallbackChallenge validates that the nodeup BootstrapRequest carries a fully populated Challenge before running the callback challenge flow. If bootstrapRequest.Challenge is nil, there is nothing to respond with, so the client aborts immediately with 'challenge not set'. The server did not provide (or the nodeup code did not copy) the challenge into the request.","triggerScenarios":"bootstrap calls DoCallbackChallenge with a BootstrapRequest whose Challenge field is nil — e.g. the server response omitted the challenge, or the nodeup version predates challenge support and never populates it.","commonSituations":"Version skew between nodeup binary and kops controller (challenge feature added later); server not running with challenge enforcement so no challenge is issued; custom bootstrap flows constructing BootstrapRequest manually without Challenge.","solutions":["Ensure nodeup and the kops server are from the same kops version (challenge support must exist on both sides)","Check the server actually issues challenges (NewChallengeServer wired in) and includes Challenge in the bootstrap response","If the node constructs BootstrapRequest manually, populate the Challenge field from the server's response","Disable/enable challenge behavior consistently on client and server configurations"],"exampleFix":"// before\nreq := &nodeup.BootstrapRequest{ClusterName: cluster}\nclient.DoCallbackChallenge(ctx, cluster, endpoint, req) // Challenge nil\n// after\nchallenge, err := fetchChallengeFromServer(ctx)\nif err != nil { return err }\nreq := &nodeup.BootstrapRequest{ClusterName: cluster, Challenge: challenge}\nclient.DoCallbackChallenge(ctx, cluster, endpoint, req)","handlingStrategy":"validation","validationCode":"if req.Challenge == nil {\n  return errors.New(\"server did not provide a bootstrap challenge\")\n}\nif req.Challenge.ChallengeID == \"\" || len(req.Challenge.ChallengeSecret) == 0 || req.Challenge.Endpoint == \"\" {\n  return errors.New(\"bootstrap challenge incomplete\")\n}","typeGuard":"func challengeComplete(c *nodeup.Challenge) bool {\n  return c != nil && c.ChallengeID != \"\" && len(c.ChallengeSecret) > 0 && c.Endpoint != \"\"\n}","tryCatchPattern":"if err := challengeClient.DoCallbackChallenge(ctx, cluster, endpoint, req); err != nil {\n  return fmt.Errorf(\"callback challenge failed: %w\", err)\n}","preventionTips":["Keep nodeup and kops server versions aligned","Ensure the challenge server is wired into the bootstrap API","When building BootstrapRequest manually, copy the full Challenge struct from the server response"],"tags":["bootstrap","challenge","nodeup","validation"],"backgroundTag":"missing-challenge-payload","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"}