Why does the `computed_optional` nested attribute produces `inconsistent result after apply` error?

In our Terraform provider, the pf9_cluster resource supports the addons attribute, which can include configurations for various addons like coredns. The addon, in particular, has the following schema:

resource "pf9_cluster" "example" {
  name   = "example"
  addons = {
    coredns = {
      version = "1.11.1"
      params = {
        "dnsDomain": "cluster.local"

The addons and the coredns sub-attribute is of type single_nested. The version and params are marked as computed_optional , meaning they can be set by the backend API or explicitly by the practitioner in the Terraform configuration.

However, if the practitioner attempts to create the pf9_cluster resource without specifying the coredns attribute, like this:

resource "pf9_cluster" "example" {
  name   = "tf-cluster-81"
  addons = {}

The provider returns an error "Provider produced inconsistent result after apply".

provider produced an unexpected new value: .addons.coredns: was null, but now
│ cty.ObjectVal(map[string]cty.Value{"params":cty.MapVal(map[string]cty.Value{"dnsDomain":cty.StringVal("cluster.local"), "dnsMemoryLimit":cty.StringVal("170Mi")}), "phase":cty.StringVal(""),
│ "version":cty.StringVal("1.11.1")}).

This should not have happened because the coredns attribute is marked as computed_optional. The backend API automatically enables it with default settings, hence the state contains its actual value but the plan does not.

How can this error be avoided? Let’s discuss strategies and best practices for handling scenarios associated with nested attributes in Terraform. Feel free to suggest an alternate schema for this use case.

Hi @TheNilesh,

From this error message it appears that the provider did not announce the value it intended to use during the plan phase, and so Terraform raised this error during the apply phase as part of its goal of either doing exactly what was planned or raising an error if that was not possible.

There are two ways you can make this flow valid:

  1. Return the final value of this coredns attribute during the plan phase, so that Terraform can show it in the plan output for the operator to review.

    This is the preferable option if your provider has enough information during the plan phase to do it, because it tells the operator exactly what’s going to happen during the apply phase.

  2. Make the plan phase set coredns to an “unknown value”, which acts as a placeholder for a value that the provider will decide during the apply phase.

    In this case Terraform will show the attribute value as (known after apply) when presenting the plan to the operator for approval. This is not ideal but sometimes unavoidable if the decision about the final attribute value will be made by the remote API only after making the proposed change.

Your current implementation seems to be indicating during plan that the final value of the attribute will be null. (I assume you aren’t doing that explicitly, but null represents the attribute not being set at all and so that’s the value it will have if you don’t set it.)

Since that’s a known value, Terraform requires that the provider match that value exactly after the apply phase, and so I think that’s what is causing your current error.