kubernetes/kops · error

building static config

Error message

building static config: %w

What it means

During etcd-manager pod construction for bare-metal ("metal") clusters, kOps builds a StaticConfig struct (fixed etcd member list) and JSON-serializes it. If json.Marshal fails, the error is wrapped as "building static config: %w". Marshal of this in-memory struct essentially only fails if something injected unsupported types (e.g. non-serializable values via NaN floats), so this is a defensive internal error rather than a user-facing config problem.

Solutions

  1. Upgrade kOps to the latest patch release, since the wrapped marshal error points to an internal defect
  2. Inspect the wrapped inner error (%w) for the exact json.UnsupportedType/Value message to identify which field broke serialization
  3. File a kOps issue with the full cluster spec and kOps version if it reproduces on the latest release
Defensive patterns

Strategy: try-catch

Try / catch

// Go caller of buildPod
pod, err := buildPod(ctx, b, etcdCluster)
if err != nil {
    var marshalErr *json.UnsupportedTypeError
    if errors.As(err, &marshalErr) {
        klog.Errorf("static config marshal failed: %v", marshalErr)
    }
    return fmt.Errorf("etcd-manager pod build failed: %w", err)
}

Prevention

When it happens

Trigger: Running `kops create cluster`/`kops update cluster --target terraform|direct` on a cluster with cloudProvider "metal", causing buildPod (called from buildManifest) to reach the CloudProviderMetal case and call json.Marshal(staticConfig); only fails if marshal returns an error, which for this fixed struct is practically unreachable.

Common situations: Seen in bug reports about bare-metal etcd-manager clusters; almost always indicates a kOps internal bug or a corrupted in-memory cluster spec rather than a user mistake.

Related errors


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

Appendix: source

Thrown at pkg/model/components/etcdmanager/model.go:545

		case kops.CloudProviderMetal:
			config.VolumeProvider = "external"
			config.BackupStore = "file:///mnt/disks/backups"
			config.VolumeTag = []string{
				fmt.Sprintf("%s--%s--", b.Cluster.Name, etcdCluster.Name),
			}

			staticConfig := &StaticConfig{
				EtcdVersion: etcdCluster.Version,
			}
			staticConfig.Nodes = append(staticConfig.Nodes, StaticConfigNode{
				ID: fmt.Sprintf("%s--%s--%d", b.Cluster.Name, etcdCluster.Name, 0),
				// TODO: Support multiple control-plane nodes (will be interesting!)
				IP: []string{"node0" + "." + etcdCluster.Name + "." + b.Cluster.Name},
			})
			b, err := json.Marshal(staticConfig)
			if err != nil {
				return nil, fmt.Errorf("building static config: %w", err)
			}
			config.StaticConfig = string(b)

		default:
			return nil, fmt.Errorf("CloudProvider %q not supported with etcd-manager", b.Cluster.GetCloudProvider())
		}
	}

	args, err := flagbuilder.BuildFlagsList(config)
	if err != nil {
		return nil, err
	}

	{
		container.Command = []string{"/go-runner"}
		container.Args = []string{
			"--log-file=/var/log/etcd.log",
			"--also-stdout",

View on GitHub (pinned to 4c8573c808)