Custom Provider troubles - inconsistent result for Root resource

Hello everyone!

I am currently writing a small custom provider for my thesis project, and I ran into problems :frowning: the provider is supposed to create a simple resource on a local running Bitbucket.
I studied the Terraform guides about writing providers and some existing providers to understand how Terraform interacts with providers and golang itself.

I got it working, somewhat - but I run into the same problem not matter what I do. When I try to create a resource using my custom providers, this error pops up:

When applying changes to customResource, provider
“customProvider” produced an unexpected new value: Root resource
was present, but now absent.

Sadly, this error almost never comes up in the entire internet - I looked into it all day. As I understand it, the “inconsistent result after apply” error is the result of the provider changing ResourceData in a way that isn’t nessecary, so Terraform thinks a change has been made? I don’t undertand what “Root resource” refers to in this context, though.
I think the problem stems from the fact that the id of my object is an int (server-side), but Terraform forces me to use TypeString - or because it is a Computed value, or a combination of both. I convert the id into string in the resourceSomethingRead-function, of course. My logs indicate that the entire create and read operation runs into no problems: the response from the server is accepted with correct codes and all content is parsed correctly, too. But still, the error is thrown.

I looked into this all day and wasn’t able to find any answers or pointer to understanding Root resource correctly, or how the read-function works and when it is called by Terraform. I think the problem lies somewhere in there.
Did anyone ever run into similar problems, or does someone understand what the problem is? Does anyone know a provider that successfully maps an external non-string ID into Terraform?

For context, here is the full content of my relevant provider files (its really simple, or should be):
resource_project.go
provider.go
client.go

Some more context: this is what a successful POST to the server returns, the POST body contains all information but the ID (because it is exclusively computed by the server and can’t be set manually)

A colleague of mine was able to spot the problem - the fix was actually fairly simple.
In code, i used tried to set the Id field of the ResourceData like this:
d.set("id", idString)
Id is however an inherent field of ResourceData, so there is an actual setter for it, obviously
d.setId(idString)
that small mistake causes Terraform to not see the resulting object, because the id is never set, but the id also is the main identifier of the object. Such a small oversight! It’s always the smallest things. My IDE doesn’t understand import via Git-tags, so I couldn’t figure it out that way either. Oh well, maybe it will help someone else!

1 Like

Hi @naumannt! I’m sorry you ran into this confusing message, and I’m glad you were able to figure it out.

As you learned, the current SDK considers id to be a special attribute because the absense of an id is how the provider tells the SDK that an object has been deleted. In your case then, the SDK saw that your “create” function didn’t call SetId and assumed you meant that the operation had ended with no object being created. Terraform Core then complained about that result, because the absence of an object after apply disagreed with the earlier plan to create the object.

Generally-speaking, Terraform Core expects that the final result after calling the apply operation (which the SDK itself splits into separate “Create”, “Update”, “Delete” functions) will match the values shown in the plan and will reject the result if not, because values other than what were planned would otherwise cascade into the configurations for other resources and cause them to produce a result other than what was planned, which would then be hard to diagnose due to the effect being so far from the cause.

The current SDK abstracts these details away quite a bit though, including automatically generating the plan for you in most cases and this funny behavior with SetId, which in this case unfortunately led to the error message being pretty unhelpful because Terraform Core was reporting the error using its own lower-level view of things, rather than the SDK’s higher-level view of things. :confounded:

In any event, I’m glad you figured it out, and I’m sorry it wasn’t easier to understand what was going on here. The team that works on the plugin SDK is currently working on a new iteration of the API which aims to align better the SDK abstractions with Terraform Core’s assumptions, so hopefully this confusing trap will be addressed by that work.

Naumannt, Thank you so much for this. This one had me stumped too. I guess one doesn’t appreciate good error message and handling until you come across an issue like this.

Again, many thanks :pray: