Comprehensive documentation and best practices for building Terraform providers with terraform-plugin-framework (v1.17.0). Covers providers, resources, schemas, types, validators, testing, and common pitfalls.
Overall
score
97%
Always check resp.Diagnostics.HasError() after any operation that appends diagnostics, and return early.
Check diagnostics and return early after:
req.Plan.Get(), req.State.Get(), req.Config.Get()resp.State.Set()Reading plan (resources):
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}Reading config (data sources):
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}Setting state (always check, even as the last statement in a function):
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}A data source Read method must check diagnostics after Config.Get, handle not-found with AddError (not RemoveResource), and check diagnostics after State.Set:
func (d *ExampleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config ExampleDataSourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
item, err := d.client.GetItem(config.Id.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Item Not Found",
fmt.Sprintf("Could not find item with ID %s: %s", config.Id.ValueString(), err),
)
return
}
config.Name = types.StringValue(item.Name)
resp.Diagnostics.Append(resp.State.Set(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
}return after adding an error diagnosticUse AddAttributeError with a path for field-level context instead of generic AddError.
Never continue execution after appending error diagnostics. Never silently ignore errors from Plan/State/Config reads.
See Resources for complete CRUD examples with diagnostics.