From b6b4c59a7304a0161eef9bc4f9f88b387e41c0af Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Tue, 16 Jul 2024 16:14:30 -0700 Subject: [PATCH] configs: Include context when variable default has nested problem Previously this error message was including only the main error message and ignoring any context about what part of a potential nested data structure it arose from. Now we'll use our usual path formatting utility to introduce additional context whenever a problem arises with a nested value. --- internal/configs/named_values.go | 8 +++-- internal/configs/named_values_test.go | 50 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 internal/configs/named_values_test.go diff --git a/internal/configs/named_values.go b/internal/configs/named_values.go index ad82960fe3f3..1d593c9b3703 100644 --- a/internal/configs/named_values.go +++ b/internal/configs/named_values.go @@ -14,6 +14,7 @@ import ( "github.com/zclconf/go-cty/cty/convert" "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/tfdiags" ) // A consistent detail message for all "not a valid identifier" diagnostics. @@ -163,8 +164,11 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno diags = append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid default value for variable", - Detail: fmt.Sprintf("This default value is not compatible with the variable's type constraint: %s.", err), - Subject: attr.Expr.Range().Ptr(), + Detail: fmt.Sprintf( + "This default value is not compatible with the variable's type constraint: %s.", + tfdiags.FormatError(err), + ), + Subject: attr.Expr.Range().Ptr(), }) val = cty.DynamicVal } diff --git a/internal/configs/named_values_test.go b/internal/configs/named_values_test.go new file mode 100644 index 000000000000..0626157c031e --- /dev/null +++ b/internal/configs/named_values_test.go @@ -0,0 +1,50 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package configs + +import ( + "testing" + + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" +) + +func TestVariableInvalidDefault(t *testing.T) { + src := ` + variable foo { + type = map(object({ + foo = bool + })) + + default = { + "thingy" = { + foo = "string where bool is expected" + } + } + } + ` + + hclF, diags := hclsyntax.ParseConfig([]byte(src), "test.tf", hcl.InitialPos) + if diags.HasErrors() { + t.Fatal(diags.Error()) + } + + _, diags = parseConfigFile(hclF.Body, nil, false, false) + if !diags.HasErrors() { + t.Fatal("unexpected success; want error") + } + + for _, diag := range diags { + if diag.Severity != hcl.DiagError { + continue + } + if diag.Summary != "Invalid default value for variable" { + t.Errorf("unexpected diagnostic summary: %q", diag.Summary) + continue + } + if got, want := diag.Detail, `This default value is not compatible with the variable's type constraint: ["thingy"].foo: a bool is required.`; got != want { + t.Errorf("wrong diagnostic detault\ngot: %s\nwant: %s", got, want) + } + } +}