liveBook · Manning

Diagnostics object

As explained in Terraform in Depth: Infrastructure as Code with Terraform and OpenTofu

A Diagnostics object is a Terraform Plugin Framework response object that collects errors and other diagnostic messages for return to Terraform users.

A Diagnostics object is carried by the response object passed to Terraform Plugin Framework functions. It collects errors and other diagnostic messages for Terraform users, allowing a provider to explain configuration problems instead of failing opaquely. section 12.3.2

Provider code can add several diagnostics during one function call. Rather than returning after the first problem, process every value that can be checked, add each error, then return once the available validation is complete. section 12.3.2 section 12.4.3

A practical provider-configuration workflow is:

  • Read configuration into the provider model and append any diagnostics produced by that read. section 12.3.2
  • Check unknown or invalid values, using AddAttributeError to associate a message with the relevant configuration path. section 12.3.2 section 12.4.3
  • Finish processing all parameters, check HasError, and return before creating or exposing a client when errors remain. section 12.4.3

Unknown provider credential

During Configure, an unknown access token prevents client creation. Add an attribute error at the user-access-token path with a corrective message, process any other available settings, and return after checking Diagnostics.HasError. section 12.3.2 section 12.4.3

Diagnostics communicate failures to Terraform; logging communicates operational detail. Use tflog for Terraform-aware log levels and filtering, and never use fatal logging methods that could exit without returning diagnostics or could leave state corrupted. section 12.3.2

Listing 12.4 Logging and error messaging
func (p *MastodonProvider) Configure(ctx context.Context, req 
provider.ConfigureRequest, resp *provider.ConfigureResponse) {
    var data MastodonProviderModel
    tflog.Debug(ctx, "mastodon_provider configure")                      #1
    resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
 
    if data.AccessToken.IsUnknown() {
        resp.Diagnostics.AddAttributeError(                              #2
            path.Root("user-access-token"),
            "Unknown Mastodon User Password",
            "The provider cannot create the Mastodon API client as there 
is an unknown configuration value for the Mastodon User Password. "+
                "Either target apply the source of the value first, set 
the value statically in the configuration, or use the 
MASTODON_USER_PASSWORD environment variable.",
        )
    }
    access_token := os.Getenv("MASTODON_ACCESS_TOKEN")
    if !data.AccessToken.IsNull() {
        access_token = data.AccessToken.ValueString()
    }
 
    // Repeat for user_email and user_password
 
    if access_token != "" {
        ctx = tflog.SetField(ctx, "mastodon_access_token", access_token) #3
        ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, 
"mastodon_access_token")                                               #4
    } else if user_email != "" && user_password != "" {
        ctx = tflog.SetField(ctx, "mastodon_user_email", user_email)
        ctx = tflog.SetField(ctx, "mastodon_user_password", user_password)
        ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, 
"mastodon_user_password")
    } else {
        resp.Diagnostics.AddAttributeError(                              #5
            path.Root("user-access-token"),
            "Missing Mastodon Credentials",
            "The provider cannot create the Mastodon API client as neither 
the Access Token or the Username and Password fields are set.",
        )
    }
 
    if resp.Diagnostics.HasError() {                                     #6
        return
    }
 
    // Continue to configure client
}
#1 The logging lines help to understand what’s happening in the provider, but aren’t displayed by default.
#2 We can provide errors about attributes to the Diagnostics object, which will be displayed to the user.
#3 We can log the access token to help with debugging.
#4 We can also make sure to filter out the value from the logs.
#5 We can provide more than one error on the same flow.
#6 Before moving on we can check for errors and return early.

Inspect the Configure example showing diagnostics appended from configuration reads, attribute-specific errors, and Terraform-aware logging. section 12.3.2

How Terraform in Depth: Infrastructure as Code with Terraform and OpenTofu covers it

How deep it goes
Explains aggregation, attribute-specific errors, HasError checks, and fatal-logging hazards without detailing framework internals.
Examples
Uses Configure validation, unknown credentials, AddAttributeError, Diagnostics.Append, and HasError as concrete examples.
What it assumes
Assumes familiarity with Terraform provider functions and basic Go logging while applying Terraform-specific response and logging APIs.
What you can do after
Diagnose/debug with aggregated provider errors and corrective messages instead of terminating before Terraform receives diagnostics.
How it connects
Connects provider responses with provider configuration, error handling, logging, and Terraform Plugin Framework functions.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Terraform in Depth: Infrastructure as Code with Terraform and OpenTofu. The section links point to the parts of the book it draws on.