kubernetes/kops · error

error starting challenge listener: %w

Error message

error starting challenge listener: %w

What it means

nodeup wraps any failure from challengeServer.NewListener (which opens a TCP listener on wellknownports.NodeupChallenge for the bootstrap challenge protocol) with this message. It is thrown by getNodeConfigFromServers while setting up the challenge listener used to authenticate node bootstrap requests. If the listener cannot bind, nodeup aborts before contacting the config server.

Source

Thrown at upup/pkg/fi/nodeup/command.go:807

			return nil, err
		}
		authenticator = a

	default:
		return nil, fmt.Errorf("unsupported cloud provider for node configuration %s", bootConfig.CloudProvider)
	}

	var challengeListener *bootstrap.ChallengeListener
	if kopsmodel.UseChallengeCallback(bootConfig.CloudProvider) {
		challengeServer, err := bootstrap.NewChallengeServer(bootConfig.ClusterName, []byte(bootConfig.ConfigServer.CACertificates))
		if err != nil {
			return nil, err
		}
		listen := ":" + strconv.Itoa(wellknownports.NodeupChallenge)

		l, err := challengeServer.NewListener(ctx, listen)
		if err != nil {
			return nil, fmt.Errorf("error starting challenge listener: %w", err)
		}
		challengeListener = l
		defer challengeListener.Stop()
	}

	// Note: The url is overridden in every iteration of the loop below.
	client := kopscontrollerclient.NewWithTLSServerName(authenticator, []byte(bootConfig.ConfigServer.CACertificates), url.URL{}, bootConfig.ConfigServer.TLSServerName)
	defer client.Close()

	// Any one of these servers may be permanently unreachable from this node -- an IPv6-only
	// cluster lists the load balancer's IPv4 address alongside its IPv6 one, and only the
	// latter is routable from the nodes. So give each server a short turn and keep cycling
	// through the list, rather than spending the whole budget on whichever happens to sort first.
	client.Backoff = perServerBootstrapBackoff

	deadline := time.Now().Add(bootstrapTimeout)
	for {
		var merr error

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check what is bound to the NodeupChallenge port with `ss -ltnp | grep <port>` and kill the stale process
  2. Restart the node or the nodeup systemd unit to clear stuck listeners
  3. Verify the container/security context allows binding the port (NET_BIND_SERVICE capability)
  4. Check kernel/network errors in nodeup logs preceding this message for the underlying net.Listen cause
Defensive patterns

Strategy: fallback

Validate before calling

// before starting nodeup
const challengePort = 3989
ln, err := net.Listen("tcp", ":"+strconv.Itoa(challengePort))
if err != nil { return fmt.Errorf("challenge port %d unavailable: %w", challengePort, err) }
ln.Close()

Try / catch

if err := runNodeup(ctx); err != nil {
  if strings.Contains(err.Error(), "error starting challenge listener") {
    klog.Errorf("challenge listener port conflict; ensure port is free and rerun: %v", err)
  }
}

Prevention

When it happens

Trigger: challengeServer.NewListener fails when calling net.Listen on ":<NodeupChallenge port>" — port already in use, insufficient privileges, or network namespace/socket errors.

Common situations: Another nodeup process or leftover container already holds the challenge port; running in a restricted environment (e.g. container without NET_BIND_SERVICE); port conflicts after node reboot with stale processes.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/796b02d1153284ed. Report an issue: GitHub.