{"record":{"id":"019ff55f78793454","repo":"kubernetes/kops","slug":"reconcile-is-not-supported-with-terraform","errorCode":null,"errorMessage":"reconcile is not supported with terraform","messagePattern":"reconcile is not supported with terraform","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops/reconcile_cluster.go","lineNumber":126,"sourceCode":"\t// viper.BindPFlag(\"lifecycle-overrides\", cmd.Flags().Lookup(\"lifecycle-overrides\"))\n\t// viper.BindEnv(\"lifecycle-overrides\", \"KOPS_LIFECYCLE_OVERRIDES\")\n\t// cmd.RegisterFlagCompletionFunc(\"lifecycle-overrides\", completeLifecycleOverrides)\n\t// cmd.Flags().BoolVar(&options.Prune, \"prune\", options.Prune, \"Delete old revisions of cloud resources that were needed during an upgrade\")\n\t// 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\")\n\n\t// cmd.Flags().BoolVar(&options.Reconcile, \"reconcile\", options.Reconcile, \"Reconcile the cluster by rolling the control plane and nodes sequentially\")\n\n\treturn cmd\n}\n\n// ReconcileCluster updates the cluster to the desired state, including rolling updates where necessary.\n// To respect skew policy, it updates the control plane first, then updates the nodes.\n// \"update\" is probably now smart enough to automatically not update the control plane if it is already at the desired version,\n// but we do it explicitly here to be clearer / safer.\nfunc RunReconcileCluster(ctx context.Context, f *util.Factory, out io.Writer, options *ReconcileClusterOptions) error {\n\tc := &options.CoreUpdateClusterOptions\n\tif c.Target == cloudup.TargetTerraform {\n\t\treturn fmt.Errorf(\"reconcile is not supported with terraform\")\n\t}\n\n\tif !c.Yes {\n\t\t// A reconcile without --yes is the same as a dry run\n\t\topt := *c\n\t\tif _, err := RunCoreUpdateCluster(ctx, f, out, &opt); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n\n\tfmt.Fprintf(out, \"Updating control plane configuration\\n\")\n\t{\n\t\topt := *c\n\t\topt.InstanceGroupRoles = []string{\n\t\t\tstring(kops.InstanceGroupRoleAPIServer),\n\t\t\tstring(kops.InstanceGroupRoleControlPlane),\n\t\t}","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops/reconcile_cluster.go#L108-L144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove the terraform target (set Target to \"direct\" or leave it empty) in the ReconcileClusterOptions before calling RunReconcileCluster.","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.","In wrapper scripts, ensure flags meant for `kops update` (especially --target) are not forwarded to `kops reconcile cluster`.","If reconcile must support terraform in your workflow, file/upvote an upstream kOps feature request — it is explicitly unsupported today."],"exampleFix":"// before\nopt := &ReconcileClusterOptions{}\nopt.CoreUpdateClusterOptions.Target = cloudup.TargetTerraform\nerr := RunReconcileCluster(ctx, f, out, opt) // \"reconcile is not supported with terraform\"\n// after\nopt := &ReconcileClusterOptions{}\nopt.CoreUpdateClusterOptions.Target = \"direct\"\nerr := RunReconcileCluster(ctx, f, out, opt)","handlingStrategy":"validation","validationCode":"if options.CoreUpdateClusterOptions.Target == cloudup.TargetTerraform {\n    return errors.New(\"use `kops update cluster --target terraform` instead of reconcile\")\n}\nerr := RunReconcileCluster(ctx, f, out, options)","typeGuard":null,"tryCatchPattern":"err := RunReconcileCluster(ctx, f, out, options)\nif err != nil && strings.Contains(err.Error(), \"reconcile is not supported with terraform\") {\n    // fall back to update flow for terraform users\n    return RunCoreUpdateCluster(ctx, f, out, &options.CoreUpdateClusterOptions)\n}\nreturn err","preventionTips":["Never set Target on ReconcileClusterOptions; leave it at its default (direct).","Keep `--target terraform` flags in update-command-only code paths; don't share a flag set between update and reconcile.","If you manage infrastructure with terraform, model your pipeline as: kops update --target terraform + terraform apply; use reconcile only for direct targets.","Audit wrapper scripts for forwarded update flags before calling reconcile."],"tags":["reconcile","terraform","unsupported-target","cli"],"backgroundTag":"unsupported-target-terraform","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}