-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provider produced unexpected value after apply for a Computed attribute #840
Comments
hey there @mschuchard, thanks for opening the issue 👋🏻 Just wanted to let you know this is still on my radar, I just haven't found the time to recreate the issue. If others run into this bug and have a reproducible example they can share, that'd be helpful. For now, I plan on continuing to iterate on the example you shared in the discuss post here 👍🏻 |
I just started looking at the example and I have a clarifying question about the schema/data model that was provided. In the example, you have this model: // provider plugin
// tf go models
type fooModel struct {
Bar types.Object `tfsdk:"bar"`
}
type barModel struct {
Baz types.String `tfsdk:"baz"`
} This schema: Attributes: map[string]schema.Attribute{
"foo": resource.SingleNestedAttribute{
Computed: true,
Description: "The foo attributes.",
Attributes: map[string]resource.Attribute{
"bar": resource.StringAttribute{
Computed: true,
Description: "The bar.",
},
},
},
} Which is read in this Create from func (resource *fooResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
// read Terraform plan data into the model
var data util.fooModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// ... remaining logic
} I'm wondering if this was a copy/paste error? I would expect, based on the schema you provided and how you're reading the plan data, that your resource models would look like: // provider plugin
// tf go models
type resourceModel struct {
Foo types.Object `tfsdk:"foo"`
}
type fooModel struct {
Bar types.String `tfsdk:"bar"`
}
func (resource *fooResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
// read Terraform plan data into the model
var data util.resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// ... remaining logic
} |
Ok I see where the typo arose from the heavy amount of redacting and sanitization; there is an issue in the schema: Attributes: map[string]schema.Attribute{
"bar": resource.SingleNestedAttribute{
Computed: true,
Description: "The bar attributes.",
Attributes: map[string]resource.Attribute{
"baz": resource.StringAttribute{
Computed: true,
Description: "The baz.",
},
},
},
} That would probably actually deserialize and serialize for you accurately. If the TF Go models were to be renamed then the Create and Read would need to correspondingly be modified as the core issue here is for the struct field member/object type/single nested attribute. Since this issue occurs for all resources with this model/schema/type, then you could probably also devise your own MCVE if there are any other typos. |
Cool, thanks for clarifying. Apologies if I'm coming across as pedantic with the specifics of your example models/schema. As I'm still unable to reproduce the behavior, I'm trying to change as little as possible from what you've given me. Here is the example resource I ran in it's entirety from your MCVE: https://github.com/austinvalle/terraform-provider-sandbox/blob/9b559ce4fb11aaabf2b2cf0f166493d31b9ce17c/internal/provider/thing_resource.go
Running with this config: https://github.com/austinvalle/terraform-provider-sandbox/blob/9b559ce4fb11aaabf2b2cf0f166493d31b9ce17c/examples/resources/resource.tf
Output $ terraform apply -auto-approve
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:
# examplecloud_thing.this will be created
+ resource "examplecloud_thing" "this" {
+ bar = (known after apply)
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
examplecloud_thing.this: Creating...
examplecloud_thing.this: Creation complete after 0s [id=test]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ cat terraform.tfstate
{
"version": 4,
"terraform_version": "1.5.4",
"serial": 1,
"lineage": "6bd42aa5-17fb-ad89-4d52-6e018719f3a6",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "examplecloud_thing",
"name": "this",
"provider": "provider[\"registry.terraform.io/austinvalle/sandbox\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"bar": {
"baz": "baz-value"
},
"id": "test"
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
}
Output $ terraform apply -auto-approve
examplecloud_thing.this: Refreshing state... [id=test]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
$ cat terraform.tfstate
{
"version": 4,
"terraform_version": "1.5.4",
"serial": 1,
"lineage": "6bd42aa5-17fb-ad89-4d52-6e018719f3a6",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "examplecloud_thing",
"name": "this",
"provider": "provider[\"registry.terraform.io/austinvalle/sandbox\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"bar": {
"baz": "baz-value"
},
"id": "test"
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
} As I wasn't able to reproduce the error:
Appreciate your time working through this 👋🏻 |
func BarGoToTerraform(ctx context.Context, b Bar) (types.Object, diag.Diagnostics) {
return types.ObjectValueFrom(ctx, barModelTF, barModel{
Baz: types.StringValue(b.Baz),
})
} The primary difference here being my usage of the intrinsic converter Also if this is root cause then this relates to #822 where I offered to contribute more complex examples and algorithms for review and then addition to documentation but received no reply. The documentation currently recommends the usage of I know there are generally issues with availability for reviewing PR (same occurs in other TF projects, and Packer and Vault projects), and so I do understand why there was no reply to my offer of assistance. I would request the offer is accepted if you verify this is root cause however. Thank you. |
I don't think it necessarily is significant in-terms of "you should be using one vs. the other". Using You can replace the stub function with the following and achieve the same results (updated sandbox example): func DoFoo(client any, method string, id string) (Foo, error) {
return Foo{
Bar: Bar{
Baz: "using-object-from-now",
},
}, nil
}
func BarGoToTerraform(ctx context.Context, b Bar) (types.Object, diag.Diagnostics) {
return types.ObjectValueFrom(ctx, barModelTF, barModel{
Baz: types.StringValue(b.Baz),
})
} Output $ terraform apply -auto-approve
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:
# examplecloud_thing.this will be created
+ resource "examplecloud_thing" "this" {
+ bar = (known after apply)
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
examplecloud_thing.this: Creating...
examplecloud_thing.this: Creation complete after 2s [id=test]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ cat terraform.tfstate
{
"version": 4,
"terraform_version": "1.5.4",
"serial": 1,
"lineage": "3e6bd6de-387f-1dd9-bcb2-65e2f578860b",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "examplecloud_thing",
"name": "this",
"provider": "provider[\"registry.terraform.io/austinvalle/sandbox\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"bar": {
"baz": "using-object-from-now"
},
"id": "test"
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
}
$ terraform apply -auto-approve
examplecloud_thing.this: Refreshing state... [id=test]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
$ cat terraform.tfstate
{
"version": 4,
"terraform_version": "1.5.4",
"serial": 1,
"lineage": "3e6bd6de-387f-1dd9-bcb2-65e2f578860b",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "examplecloud_thing",
"name": "this",
"provider": "provider[\"registry.terraform.io/austinvalle/sandbox\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"bar": {
"baz": "using-object-from-now"
},
"id": "test"
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
} I'm not 100% sure this is the root cause of your problem, but I also don't have any other ideas based on what we've looked at so far. If there's more detail you can provide about the schema/CRUD functionality that hasn't been shared then I can look further. I'll also bring this up with some of my teammates later this week and see if there are any other ideas.
As for this, we try our best to respond to requests, although it's less likely for us to find comments on merged PRs after the fact. If you'd like to open up a new issue to discuss further (more complex) documentation updates I think that'd be great! We do try to keep the docs simple where possible, but always welcome to hear potential improvements. |
So now the MCVE functionality does match the code, and that is concerning. The first thought would probably be matching the environment, but this is occurring for myself and the users for all resources with this structure across different operating systems, Terraform versions >= 1.2.0 < 1.6.0, and versions of Go within the minor of 1.20. Then it becomes possibly bizarre differences that I would think should have no effect such as that my schema for A couple of questions though:
Thank you. |
ContextSince I'm going to reference the Terraform Resource lifecycle and the related RPCs in this response, here are helpful references that describe them:
Answering Questions
|
I'll talk through this problem with a teammate and see if I can get any other ideas for recreating the behavior you're describing |
Yes thank you very likely that. I have been playing around with provider development since the days of direct package imports, but only began doing anything beyond toys with this plugin framework, and so I probably conflated the four different iterations here.
Would that not cause the following to fail though because it is passing: ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectUnknownValue("provider_foo.test", tfjsonpath.New("bar")),
},
}, I did observe that changing
which was super weird to me and makes me question the test outcome. |
Based on how you described your error, I would expect this to pass successfully, but the test would fail due to your I would expect that plancheck assertion to fail on ConfigPlanChecks: resource.ConfigPlanChecks{
PostApplyPreRefresh: []plancheck.PlanCheck{
plancheck.ExpectUnknownValue("provider_foo.test", tfjsonpath.New("bar")),
},
},
This looks like a bug in the error message of that plan check when the attribute is nil, I actually can recreate that with this new test where I'm forcing the Terraform core "inconsistent value" error for our MCVE: --- FAIL: Test (0.22s)
/Users/austin.valle/code/terraform-provider-sandbox/internal/provider/thing_resource_test.go:17: Step 1/1 error: Pre-apply plan check(s) failed:
path not found: specified key bar not found in map
FAIL
FAIL github.com/austinvalle/terraform-provider-sandbox/internal/provider 0.506s Further inspection shows that the attribute does exist, but it's nil I will write up an issue for --- FAIL: Test (0.22s)
/Users/austin.valle/code/terraform-provider-sandbox/internal/provider/thing_resource_test.go:17: Step 1/1 error: Pre-apply plan check(s) failed:
specified key bar is nil, expected unknown
FAIL
FAIL github.com/austinvalle/terraform-provider-sandbox/internal/provider 0.506s |
It fails with that error message during initial apply for users and during acceptance testing for myself (equivalent to initial apply?). Based on the discussion thus far I believe this strongly implies we can discard |
Alright, so I spoke with one of my teammates and I'm still thinking that there is something affecting your
Since the code you're working with is proprietary and you believe the MCVE I presented is pretty close to the code exhibiting this bug, I'd like to see if you can recreate the bug using the MCVE in my github repo: Here is the commit that is currently not exhibiting the bug that you can pull to your local machine and run: https://github.com/austinvalle/terraform-provider-sandbox/tree/0dcb5af2c256d3931ea87ee99b67bf89c47cb356 I also added a commented-out line that will shows how this error can be caused by an "errant" plan modification: https://github.com/austinvalle/terraform-provider-sandbox/blob/0dcb5af2c256d3931ea87ee99b67bf89c47cb356/internal/provider/thing_resource.go#L74 - If you want to see the error purposefully, you can uncomment that line and run the acceptance test, which'll show: --- FAIL: TestThingResource (0.31s)
/Users/austin.valle/code/terraform-provider-sandbox/internal/provider/thing_resource_test.go:15: Step 1/1 error: Error running apply: exit status 1
Error: Provider produced inconsistent result after apply
When applying changes to examplecloud_thing.this, provider
"provider[\"registry.terraform.io/hashicorp/examplecloud\"]" produced an
unexpected new value: .bar: was null, but now
cty.ObjectVal(map[string]cty.Value{"baz":cty.StringVal("baz-for-the-foo")}).
This is a bug in the provider, which should be reported in the provider's own
issue tracker. If you're able to re-create this bug with the MCVE provided without a plan modifier or default value, please let me know so I can investigate further. |
Real quick sidebar that I just noticed is that the error message thrown for me on the plan test was:
and not:
I believe your discussed issue of a perhaps misleading error message is different than what I uncovered as your debug output confirms my test should pass the |
I did clone and execute an acceptance test, and then uncommented the line and executed the acceptance test again. Unfortunately that triggered a missing package import error:
Regardless of this, I am unsure of the value of this experiment as all it would do is lend credence to a hypothesis that this is an environment issue. However, we are seeing this for all resources in all environments. I believe what is more likely here by mathematical logic/scientific reasoning is that this statement:
is likely false. We are seeing this error thrown for a computed attribute where the schema contains no plan modifiers or default values of any kind. One of the resources does contain: PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
}, for the I actually repped Hashicorp while working with this company previously, and so I know they have previously shared code with Hashicorp. At this point I believe that may be the only real path forward here. What is unclear to me is how legally or for your time this would possibly fit under their TFE support contract (if at all). Alternatively I will begin experimenting with ignoring/circumventing the thrown error as I am convinced it is a false positive since the logs show the attribute is correctly computed, and according to |
Bit of a breakthrough executing acceptance tests this morning: the exact same inputs began producing different behavior in a different resource. While this normally would be sanity-reducing (or because the API was silently updated), it actually provoked a path forward on the resource with the plan modifier. I had a stupid moment and was marking the One weird behavior I did notice is that a The unfortunate part of this is that this is NOT the resource represented in the MCVE above, and that resource represented by the MCVE is still exhibiting the behavior. The encouraging aspect of this is that the issue is probably centralized to the MCVE, and not all resources defined using the |
Ok I can confirm the resource(s) in question (not the MCVE though) are now "good to go" except for an optional |
re: I worked around it by just setting the attribute to re: this issue It is only occurring for this resource now thanks to my realization that the API was behaving differently from documentation, and that I should scrutinize the error messages from the plugin framework for the actual root cause and not believe what I read. The customer is fine with not using this resource for the time being, and will instead be using the data source. Hopefully this issue will be fixed indirectly in an update, but otherwise this can be triaged probably. |
Hi @mschuchard 👋 I'm going through this issue tracker to ensure that there are actionable items in the backlog or otherwise closing them. It is a little unclear to me about the current status of this issue. Are you still having trouble and if so, can you let us know exactly what you are looking for in your situation? Thanks. |
This issue is still outstanding as far as all of us involved know, but I implemented a workaround and the plugin was successfully delivered to and accepted by the client. |
Okay, thanks for the quick reply, @mschuchard. I chatted with @austinvalle and since we do not have a working reproduction to base any potential documentation or code changes, I am not sure what we can do further in this case. I am going to close this issue for now, but if you or someone else has a working reproduction case for this type of error, please open a new issue and we will be happy to investigate it further. 👍 |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. |
This has been a discussion on plugin development for about two weeks with evidence leading to believe this more likely an issue than not, no hypothetical root cause or workaround, and the affected users in this situation are of interest to Hashicorp from a business perspective. I am therefore opening an issue here based on the above.
Module version
Relevant provider source code
See link to Hashicorp discuss.
Terraform Configuration Files
See link to Hashicorp discuss.
Debug Output
I cannot provide this easily as this is proprietary/NDA, but something could possibly be worked out if need be.
Expected Behavior
The plugin framework sets a Computed attribute to unknown during plan, and then allows setting the state to the correct actual values within the Create and/or Read.
Actual Behavior
If we are to believe the results of
terraform-plugin-testing 1.5.1
, and based on discussion thus far, then the Computed attribute value is set tounknown
, then tonull
for unknown reasons post-plan creation (issue is here), and then to the correct accurate value. The plugin framework throws this behavior as an error during theState.set()
. Error string is:Note the post-apply value is the expected and accurate value for the attribute according to the logs.
Steps to Reproduce
apply any resource with a nested type struct in the top level model that is also a schema nested attribute and tftype types.Object
References
n/a
The text was updated successfully, but these errors were encountered: