kubernetes/kops · error

reconcile is not supported with terraform

Error message

reconcile is not supported with terraform

What it means

RunReconcileCluster rejects the terraform target up front: `kops reconcile cluster` performs a sequence of live updates and rolling restarts against the running cluster, which is incompatible with generating terraform output. When CoreUpdateClusterOptions.Target is cloudup.TargetTerraform (i.e. `--target terraform` was effectively set) the command returns this error instead of running. It is an intentional, unconditional guard, not a runtime failure.

Solutions

  1. Remove the terraform target (set Target to "direct" or leave it empty) in the ReconcileClusterOptions before calling RunReconcileCluster.
  2. If you need terraform-managed infrastructure, run `kops update cluster --target terraform` instead of reconcile, and apply the plan with terraform; use reconcile only for direct in-place updates.
  3. In wrapper scripts, ensure flags meant for `kops update` (especially --target) are not forwarded to `kops reconcile cluster`.
  4. If reconcile must support terraform in your workflow, file/upvote an upstream kOps feature request — it is explicitly unsupported today.

Example fix

// before
opt := &ReconcileClusterOptions{}
opt.CoreUpdateClusterOptions.Target = cloudup.TargetTerraform
err := RunReconcileCluster(ctx, f, out, opt) // "reconcile is not supported with terraform"
// after
opt := &ReconcileClusterOptions{}
opt.CoreUpdateClusterOptions.Target = "direct"
err := RunReconcileCluster(ctx, f, out, opt)
Defensive patterns

Strategy: validation

Validate before calling

if options.CoreUpdateClusterOptions.Target == cloudup.TargetTerraform {
    return errors.New("use `kops update cluster --target terraform` instead of reconcile")
}
err := RunReconcileCluster(ctx, f, out, options)

Try / catch

err := RunReconcileCluster(ctx, f, out, options)
if err != nil && strings.Contains(err.Error(), "reconcile is not supported with terraform") {
    // fall back to update flow for terraform users
    return RunCoreUpdateCluster(ctx, f, out, &options.CoreUpdateClusterOptions)
}
return err

Prevention

When it happens

Trigger: Invoking reconcile with a configuration whose update target is terraform — e.g. programmatically building ReconcileClusterOptions with CoreUpdateClusterOptions.Target = cloudup.TargetTerraform, or wrapping/reusing update flags that had `--target terraform` set. Note the reconcile CLI currently does not expose a --target flag, so this mainly occurs in code that embeds the options.

Common situations: Scripts or tooling that construct shared update options (defaulting Target to terraform) and then call RunReconcileCluster; refactored automation reusing the update command's flag set for reconcile; copying update-command invocation patterns (update --target terraform) onto the reconcile command.

Related errors


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

Appendix: source

Thrown at cmd/kops/reconcile_cluster.go:126

	// viper.BindPFlag("lifecycle-overrides", cmd.Flags().Lookup("lifecycle-overrides"))
	// viper.BindEnv("lifecycle-overrides", "KOPS_LIFECYCLE_OVERRIDES")
	// cmd.RegisterFlagCompletionFunc("lifecycle-overrides", completeLifecycleOverrides)
	// cmd.Flags().BoolVar(&options.Prune, "prune", options.Prune, "Delete old revisions of cloud resources that were needed during an upgrade")
	// cmd.Flags().BoolVar(&options.IgnoreKubeletVersionSkew, "ignore-kubelet-version-skew", options.IgnoreKubeletVersionSkew, "Setting this to true will force updating the kubernetes version on all instance groups, regardles of which control plane version is running")

	// cmd.Flags().BoolVar(&options.Reconcile, "reconcile", options.Reconcile, "Reconcile the cluster by rolling the control plane and nodes sequentially")

	return cmd
}

// ReconcileCluster updates the cluster to the desired state, including rolling updates where necessary.
// To respect skew policy, it updates the control plane first, then updates the nodes.
// "update" is probably now smart enough to automatically not update the control plane if it is already at the desired version,
// but we do it explicitly here to be clearer / safer.
func RunReconcileCluster(ctx context.Context, f *util.Factory, out io.Writer, options *ReconcileClusterOptions) error {
	c := &options.CoreUpdateClusterOptions
	if c.Target == cloudup.TargetTerraform {
		return fmt.Errorf("reconcile is not supported with terraform")
	}

	if !c.Yes {
		// A reconcile without --yes is the same as a dry run
		opt := *c
		if _, err := RunCoreUpdateCluster(ctx, f, out, &opt); err != nil {
			return err
		}
		return nil
	}

	fmt.Fprintf(out, "Updating control plane configuration\n")
	{
		opt := *c
		opt.InstanceGroupRoles = []string{
			string(kops.InstanceGroupRoleAPIServer),
			string(kops.InstanceGroupRoleControlPlane),
		}

View on GitHub (pinned to 4c8573c808)