kubernetes/kops · error

server group task for instance group %q has unexpected type

Error message

server group task for instance group %q has unexpected type %T

What it means

After successfully fetching the ServerGroup task in HCloudClusterConfig, the code type-asserts it to *hetznertasks.ServerGroup. If the task stored under that name is a different type, the assertion fails and this error reports the actual Go type %T found.

Source

Thrown at upup/pkg/fi/cloudup/template_functions.go:1198

		NodeConfigs: map[string]hcloudNodeConfig{},
	}

	for _, ig := range tf.KopsModelContext.InstanceGroups {
		if !ig.Spec.Role.HasNode() {
			continue
		}
		if ig.Spec.Autoscale != nil && !fi.ValueOf(ig.Spec.Autoscale) {
			continue
		}

		task, err := tf.Task("ServerGroup", ig.Name)
		if err != nil {
			return "", fmt.Errorf("finding server group task for instance group %q: %w", ig.Name, err)
		}

		serverGroup, ok := task.(*hetznertasks.ServerGroup)
		if !ok {
			return "", fmt.Errorf("server group task for instance group %q has unexpected type %T", ig.Name, task)
		}

		nodeLabels, err := nodelabels.BuildNodeLabels(tf.Cluster, ig)
		if err != nil {
			return "", fmt.Errorf("building node labels for instance group %q: %w", ig.Name, err)
		}

		userDataBytes, err := fi.ResourceAsBytes(serverGroup.UserData)
		if err != nil {
			return "", fmt.Errorf("reading user-data for instance group %q: %w", ig.Name, err)
		}

		var taints []corev1.Taint
		for _, taintSpec := range ig.Spec.Taints {
			parsed, err := util.ParseTaint(taintSpec)
			if err != nil {
				return "", fmt.Errorf("parsing taints for instance group %q: %w", ig.Name, err)
			}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the task registered as "ServerGroup" for the instance group is hetznertasks.ServerGroup (use stock Hetzner model templates).
  2. Sync kOps binary and model/templates to the same version.
  3. If forking, keep the task type and name consistent with HCloudClusterConfig's assertion.

Example fix

// before (custom template)
task := &hetznertasks.ServerGroupVolume{Name:...}
// after
task := &hetznertasks.ServerGroup{Name:...}
Defensive patterns

Strategy: type-guard

Validate before calling

// Go: pre-check the registered task type before use
task, _ := tf.Task("ServerGroup", ig.Name)
if _, ok := task.(*hetznertasks.ServerGroup); !ok && task != nil {
    return fmt.Errorf("ServerGroup/%s registered as unexpected %T", ig.Name, task)
}

Type guard

// Go
func asServerGroup(t fi.Task) (*hetznertasks.ServerGroup, bool) {
    sg, ok := t.(*hetznertasks.ServerGroup)
    return sg, ok
}

Prevention

When it happens

Trigger: A task named ServerGroup/<ig.Name> exists in the context but was registered by different code/templates as another task type — e.g. custom/overridden Hetzner templates registering a different struct under the same task name.

Common situations: Customized model templates conflicting with built-in task names; running mixed kOps versions (binary newer than templates or vice versa); local forks renaming the task struct.

Related errors


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