kubernetes/kops · error

providerID was not set for node %s

Error message

providerID was not set for node %s

What it means

IdentifyNode resolves a Kubernetes Node to GCE instance identity info. It requires node.Spec.ProviderID to be set, because all subsequent lookups (project/zone/instance parsing and GCE API queries) derive from that string. If the providerID field is empty, there is nothing to identify the node with, so it fails fast.

Source

Thrown at pkg/nodeidentity/gce/identify.go:99

		}
		klog.Infof("Found project=%q", project)
	}

	return &nodeIdentifier{
		computeService: computeService,
		project:        project,
		clusterName:    clusterName,
		capiManager:    capiManager,
	}, nil
}

// IdentifyNode queries GCE for the node identity information
func (i *nodeIdentifier) IdentifyNode(ctx context.Context, node *corev1.Node) (*nodeidentity.Info, error) {
	// log := klog.FromContext(ctx)

	providerID := node.Spec.ProviderID
	if providerID == "" {
		return nil, fmt.Errorf("providerID was not set for node %s", node.Name)
	}
	if !strings.HasPrefix(providerID, "gce://") {
		return nil, fmt.Errorf("providerID %q not recognized for node %s", providerID, node.Name)
	}

	tokens := strings.Split(strings.TrimPrefix(providerID, "gce://"), "/")
	if len(tokens) != 3 {
		return nil, fmt.Errorf("providerID %q not recognized for node %s", providerID, node.Name)
	}

	project := tokens[0]
	zone := tokens[1]
	instanceName := tokens[2]

	if project != i.project {
		return nil, fmt.Errorf("providerID %q did not match our project %q", providerID, i.project)
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the GCE cloud-controller-manager is running and has annotated/patched the Node (check that node.spec.providerID looks like gce://project/zone/instance-name).
  2. Wait for node initialization: newly joined nodes get their providerID set shortly after registration; re-run identification after reconciliation.
  3. If constructing the Node yourself (tests/tools), set Spec.ProviderID explicitly to "gce://<project>/<zone>/<instance>".
  4. Check kubelet flags: on GCE the kubelet/cloud provider must not run with --cloud-provider=none, which skips providerID assignment.

Example fix

// before
node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: "gke-node-1"}}
info, err := identifier.IdentifyNode(ctx, node) // errors: providerID was not set
// after
node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: "gke-node-1"}, Spec: corev1.NodeSpec{ProviderID: "gce://my-project/us-central1-a/gke-node-1"}}
info, err := identifier.IdentifyNode(ctx, node)
Defensive patterns

Strategy: validation

Validate before calling

if node.Spec.ProviderID == "" {
    return fmt.Errorf("skip node %s: providerID not yet set", node.Name)
}
_ = identifier.IdentifyNode(ctx, node)

Type guard

func hasProviderID(node *corev1.Node) bool {
    return node != nil && node.Spec.ProviderID != ""
}

Try / catch

info, err := identifier.IdentifyNode(ctx, node)
if err != nil {
    if strings.Contains(err.Error(), "providerID was not set") {
        // requeue: providerID usually appears shortly after node registration
        return requeueAfter(10 * time.Second)
    }
    return err
}

Prevention

When it happens

Trigger: Calling IdentifyNode (directly or via the node-authorizer/identity controller) with a *corev1.Node whose Spec.ProviderID is "" — typically because the cloud-controller-manager or kubelet never populated it.

Common situations: Nodes registered by kubelet before the cloud provider integration set the provider ID; clusters where --cloud-provider=external is misconfigured so the GCE cloud controller never patches node.Spec.ProviderID; manually created Node objects in tests or fixtures; node objects restored from etcd backups missing spec updates.

Related errors


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