kubernetes/kops · error
challenge not set
Error message
challenge not set
What it means
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.
Source
Thrown at pkg/bootstrap/challenge_client.go:71
}, c.keystore)
if err != nil {
return nil, fmt.Errorf("error creating certificate: %w", err)
}
// TODO: Caching and rotation
clientCertificate := &tls.Certificate{
PrivateKey: privateKey.Key,
Certificate: [][]byte{certificate.Certificate.Raw},
Leaf: certificate.Certificate,
}
return clientCertificate, nil
}
func (c *ChallengeClient) DoCallbackChallenge(ctx context.Context, clusterName string, targetEndpoint string, bootstrapRequest *nodeup.BootstrapRequest) error {
challenge := bootstrapRequest.Challenge
if challenge == nil {
return fmt.Errorf("challenge not set")
}
if challenge.ChallengeID == "" {
return fmt.Errorf("challenge.id not set")
}
if len(challenge.ChallengeSecret) == 0 {
return fmt.Errorf("challenge.secret not set")
}
if challenge.Endpoint == "" {
return fmt.Errorf("challenge.endpoint not set")
}
if len(challenge.ServerCA) == 0 {
return fmt.Errorf("challenge.ca not set")
}
clientCertificate, err := c.getClientCertificate(ctx, clusterName)
if err != nil {
return err
}View on GitHub (pinned to 4c8573c808)
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
Example fix
// before
req := &nodeup.BootstrapRequest{ClusterName: cluster}
client.DoCallbackChallenge(ctx, cluster, endpoint, req) // Challenge nil
// after
challenge, err := fetchChallengeFromServer(ctx)
if err != nil { return err }
req := &nodeup.BootstrapRequest{ClusterName: cluster, Challenge: challenge}
client.DoCallbackChallenge(ctx, cluster, endpoint, req) Defensive patterns
Strategy: validation
Validate before calling
if req.Challenge == nil {
return errors.New("server did not provide a bootstrap challenge")
}
if req.Challenge.ChallengeID == "" || len(req.Challenge.ChallengeSecret) == 0 || req.Challenge.Endpoint == "" {
return errors.New("bootstrap challenge incomplete")
} Type guard
func challengeComplete(c *nodeup.Challenge) bool {
return c != nil && c.ChallengeID != "" && len(c.ChallengeSecret) > 0 && c.Endpoint != ""
} Try / catch
if err := challengeClient.DoCallbackChallenge(ctx, cluster, endpoint, req); err != nil {
return fmt.Errorf("callback challenge failed: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- challenge.id not set
- building nodeConfig for instanceGroup: %w
- unsupported cloud provider for authenticator %q
- no keypairID for %q
- challenge.secret not set
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/e056af41a3a9caba.
Report an issue: GitHub.