linode/terraform-provider-linode

[Bug]: Value Conversion Error

Closed this issue · 10 comments

Terraform Version

Terraform v1.9.2 on darwin_arm64

Linode Provider Version

2.25.0

Effected Terraform Resources

linode_object_storage_key

Terraform Config Files

resource "linode_object_storage_key" "this" {
  label = "<name>"

  bucket_access {
    bucket_name = "<name>"
    cluster     = "<region>"
    permissions = "read_only"
  }
}

Debug Output

No response

Panic Output

No response

Expected Behavior

Access key created/refreshed as usual

Actual Behavior

Terraform crashes with error

│ Error: Value Conversion Error

│ with module.vault-snapshot-bucket.module.access_key.linode_object_storage_key.this,
│ on .terraform/modules/vault-snapshot-bucket/linode-object-storage/access-key/main.tf line 16, in resource "linode_object_storage_key" "this":
│ 16: resource "linode_object_storage_key" "this" {

│ An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:

│ Received unknown value, however the target type cannot handle unknown values. Use the corresponding types package type or a custom type that handles
│ unknown values.

│ Path: bucket_access
│ Target Type: []objkey.BucketAccessModelEntry
│ Suggested Type: basetypes.SetValue

Resolved by downgrading to provider version 2.23.1 for now

Steps to Reproduce

Apply linode_object_storage_key using provider version 2.25.0

Hi @Aransh, thanks for reporting the issue!
You can define the key as a block rather than a nested attribute in HashiCorp Configuration Language (HCL), because latter is not currently supported.

resource "linode_object_storage_key" "this" {
  label = "test-key"

  bucket_access {
    bucket_name = "test-zhiwei-bk"
    cluster     = "us-mia-1"
    permissions = "read_only"
  }
}

The difference is that bucket_access {...} vs bucket_access = {...}

Let me know if you still have any question or issue.

@zliang-akamai sorry my bad, it is a block in my config, it's just that I use a custom module so I tried to replicate the resource directly for an example, fixed now.
Anyway I've been using this resource for ~ 1.5 years, and as I mentioned it's working on the provider's previous version, and you can see terraform logs specify this is a problem with the provider

Hi @Aransh,
I try the example I mentioned above. I create it in provider v2.23.1 and refresh it in v2.25.0, and I couldn't see the issue.

Do you have a more detailed way for reproducing the issue?

Hmmm... odd, perhaps my example was indeed not enough (As I mentioned I just improvised a quick resource, figured it happens with any access key)

I got this report from employees on other Akamai teams as well so I figure it's nothing related to our module or logic, I'll have to take a deeper look and see if I can find exactly how to replicate

Hi @Aransh, is that error directly from Terraform or another tool wrapping our Terraform provider (e.g., Crossplane)? The error message suggests that it received an Unknown value, which is not quite possible because our schema implies the bucket_access set will never be an Unknown.

Can you maybe try terraform refresh or tofu refresh?

And can we get the actual config and state that is complaining this error? If you feel it's not okay to share the state/config on a public GitHub issue, you are welcome to drop an email to us. dev-dx@linode.com

Directly from terraform.
I'll try and find a clearer clue to what's going on here next week and get back to you, but whatever it is, it changed in the last provider version

@Aransh, thanks for confirming! And yes, we did change multiple object storage resources in #1492, released in 2.24.0, but we didn't observe any issue so far.

@zliang-akamai it took a long while to narrow down the most minimal way to reproduce this issue, but I think I've narrowed it down.
Only instance where I could replicate it was when:

  • Using linode_object_storage_key
  • As part of a module
  • Which generates bucket_access using dynamic block

I suppose at least part of this is irrelevant, but I guess you being able to replicate is the most important thing.

Anyway, here is the minimal relevant code for replication:

First, create a main terraform configuration, calling a module:
Note provider version is commented, so we are using latest (2.25.0)

terraform {
  required_providers {
    linode = {
      source = "linode/linode"
      # version = "2.23.1"
    }
  }
}

module "test" {
  source = "./access-key"
  
  shards_count = 6
}

Next, create the "access-key" module directory, containing only a single file:

terraform {
  required_providers {
    linode = {
      source = "linode/linode"
    }
  }
}

variable "shards_count" {
  type = number
}

resource "linode_object_storage_key" "this" {

  label = "test"
  dynamic "bucket_access" {
    
    for_each = range(var.shards_count)

    content {
      bucket_name = "test"
      region      = "us-iad-1"
      # cluster     = "us-east-1"
      permissions = "read_only"
    }
  }
}

That's all, run init+apply, and you shall receive my error:

╷
│ Error: Value Conversion Error
│
│   with module.test.linode_object_storage_key.this,
│   on access-key/main.tf line 13, in resource "linode_object_storage_key" "this":
│   13: resource "linode_object_storage_key" "this" {
│
│ An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:
│
│ Received unknown value, however the target type cannot handle unknown values. Use the corresponding `types` package type or a custom type that handles unknown values.
│
│ Path: bucket_access
│ Target Type: []objkey.BucketAccessModelEntry
│ Suggested Type: basetypes.SetValue

Note again that the error explicitly says "This is always an error in the provider. Please report the following to the provider developer".

This is all pretty standard terraform code and functionality with for_each.
Now, uncomment the version restraint, and replace "region" with "cluster" to use the old version of the provider, and now this works:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.test.linode_object_storage_key.this will be created
  + resource "linode_object_storage_key" "this" {
      + access_key = (known after apply)
      + id         = (known after apply)
      + label      = "test"
      + limited    = (known after apply)
      + secret_key = (sensitive value)

      + bucket_access {
          + bucket_name = "test"
          + cluster     = "us-east-1"
          + permissions = "read_only"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

I hope this helps, please let me know if there's anything else I can help with

@Aransh, thank you so much for the detailed info! I think this might be an issue within HashiCorp Terraform or Terraform Framework because according to the docs, a non-computed set nested block should never receive a Unknown value in CRUD functions, which caused the conversion failure.

by the time a resource is expected to be created, read, updated, or deleted, only its computed attributes can be unknown. The rest are guaranteed to have known values (or be null).

https://developer.hashicorp.com/terraform/plugin/framework/handling-data/terraform-concepts#unknown-values

I am following up with @hashicorp's team on this issue in hashicorp/terraform-plugin-framework#1025

@zliang-akamai I did have my suspicions terraform could be the issue here (especially when I found it only happens inside a module), but they did go the extra mile to specifically note "this is always an issue with the provider", way to deflect 😂

Anyway, glad we were able to get to the bottom of this, hopefully it'll be resolved soon, thank you!