You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: website/docs/plugin/sdkv2/resources/data-consistency-errors.mdx
+77
Original file line number
Diff line number
Diff line change
@@ -110,3 +110,80 @@ This occurs if the attribute schema definition is `Optional: true` without `Comp
110
110
If the value is expected to never be set by configuration, the schema attribute `Optional: true` flag should be replaced with `Computed: true`.
111
111
112
112
Otherwise, this may not be resolvable when the resource is implemented with `terraform-plugin-sdk`. Having `Optional: true` while also setting the attribute's `Computed: true` flag in the schema will also enable this SDK's behavior of keeping the prior state value if the configuration value is removed (set to null) during an update. That SDK behavior is unavoidable. This SDK will also raise an implementation error if both `Computed: true` and `Default` are set, since the value will never reset to the default value because of that behavior. If that behavior is not acceptable, this error is unavoidable until the resource is migrated to terraform-plugin-framework, which does not have implicit behaviors when enabling the `Computed: true` flag and instead provider developers are expected to decide whether the prior state preservation behavior should occur or not by using the `UseStateForUnknown` schema plan modifier.
113
+
114
+
### Planned Value does not match Config Value
115
+
116
+
If the resource is raising this type of error or warning log:
117
+
118
+
```text
119
+
TIMESTAMP [WARN] Provider "TYPE" produced an invalid plan for ADDRESS, but we are tolerating it because it is using the legacy plugin SDK.
120
+
The following problems may be the cause of any confusing errors from downstream operations:
121
+
- .ATTRIBUTE: planned value cty.StringVal("VALUE") does not match config value cty.StringVal("value")
122
+
```
123
+
124
+
This occurs for attribute schema definitions that are `Optional: true` and `Computed: true`; where the planned value, returned by the provider, does not match the attribute's config value or prior state value. For example, value's for an attribute of type string must match byte-for-byte.
125
+
126
+
An example root cause of this issue could be from API normalization, such as a JSON string being returned from an API and stored in state with differing whitespace then what was originally in config.
127
+
128
+
#### SDKv2 Example
129
+
130
+
Here is an example of an SDKv2 resource schema and terraform config that simulates this data consistency error:
131
+
132
+
```go
133
+
functhingResource() *schema.Resource {
134
+
return &schema.Resource{
135
+
// ...
136
+
Schema: map[string]*schema.Schema{
137
+
"word": {
138
+
Type: schema.TypeString,
139
+
Optional: true,
140
+
Computed: true,
141
+
StateFunc: func(word interface{}) string {
142
+
// This simulates an API returning the 'word' attribute as all uppercase,
143
+
// which is stored to state even if it doesn't match the config or prior value.
144
+
return strings.ToUpper(word.(string))
145
+
},
146
+
},
147
+
},
148
+
}
149
+
}
150
+
```
151
+
152
+
```hcl
153
+
resource "examplecloud_thing" "this" {
154
+
word = "value"
155
+
}
156
+
```
157
+
158
+
A warning log will be produced and the resulting state after applying a new resource will be `VALUE` instead of `value`.
159
+
160
+
#### Recommended SDKv2 Solution
161
+
To solve this issue, the provider code must preserve the config value or prior state value when producing the new state. In the example above, the solution is to remove the usage of [`StateFunc`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema#Schema.StateFunc).
162
+
163
+
In use-cases where a value is normalized on return from the remote API, SDKv2 resource can implement [`DiffSuppressFunc`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema#Schema.DiffSuppressFunc) to preserve the prior state value in the case of inconsequential differences, and [`DiffSuppressOnRefresh: true`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema#Schema.DiffSuppressOnRefresh) to ensure this logic preserves the prior value during refresh.
164
+
165
+
Adding those functions to the above example would look like:
166
+
167
+
```go
168
+
functhingResource() *schema.Resource {
169
+
return &schema.Resource{
170
+
CreateContext: thingResourceCreate,
171
+
ReadContext: thingResourceRead,
172
+
UpdateContext: thingResourceUpdate,
173
+
DeleteContext: thingResourceDelete,
174
+
175
+
Schema: map[string]*schema.Schema{
176
+
"word": {
177
+
Type: schema.TypeString,
178
+
Optional: true,
179
+
Computed: true,
180
+
DiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool {
0 commit comments