Repository: gruntwork-io/terragrunt

Issue:
Add error explainer for values
Add error explainer that tells users they need the stacks experiment active if they get an error that the values variable isn't expected here.

See this error reported in discord:
https://discord.com/channels/1090098780344422490/1314225486867468309/1361095332041330789

Let's make it obvious what users should do to correct their invocation it they accidentally perform a Terragrunt operation on configurations with values until the stacks experiment is over.

Discussion:

Solution patch:
diff --git a/shell/error_explainer.go b/shell/error_explainer.go
index 16bd9e27..4fbfa577 100644
--- a/shell/error_explainer.go
+++ b/shell/error_explainer.go
@@ -27,6 +27,9 @@ var terraformErrorsMatcher = map[string]string{
 	"(?s).*NoCredentialProviders(?s).*":                                                   "Missing AWS credentials. Provide credentials to proceed.",
 	"(?s).*client: no valid credential sources(?s).*":                                     "Missing AWS credentials. Provide credentials to proceed.",
 	"(?s).*exec: \"(tofu|terraform)\": executable file not found(?s).*":                   "The executables 'terraform' and 'tofu' are missing from your $PATH. Please add at least one of these to your $PATH.",
+	"(?s).*There is no variable named \"values\"(?s).*":                                   "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\".",
+	"(?s).*Error: Reference to undeclared input variable(?s).*values(?s).*":               "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\".",
+	"(?s).*The input variable \"values\" is not declared in the root module(?s).*":        "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\".",
 }
 
 // ExplainError will try to explain the error to the user, if we know how to do so.



Test patch:
diff --git a/shell/error_explainer_test.go b/shell/error_explainer_test.go
index 7375f18f..070c3acf 100644
--- a/shell/error_explainer_test.go
+++ b/shell/error_explainer_test.go
@@ -37,6 +37,22 @@ func TestExplainError(t *testing.T) {
 			errorOutput: "exec: \"tofu\": executable file not found in $PATH",
 			explanation: "The executables 'terraform' and 'tofu' are missing from your $PATH. Please add at least one of these to your $PATH.",
 		},
+		{
+			errorOutput: "Error: Reference to undeclared input variable   on main.tf line 12, in resource \"aws_s3_bucket\" \"example\":   12:   bucket = var.values.bucket_name  An input variable with the name \"values\" has not been declared. This variable can be declared with a variable \"values\" {} block.╵",
+			explanation: "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\"",
+		},
+		{
+			errorOutput: "Error: There is no variable named \"values\"",
+			explanation: "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\"",
+		},
+		{
+			errorOutput: "Error: The input variable \"values\" is not declared in the root module on variables.tf line 3:    3:   default     = var.values.environment  Input variables can only be referenced from the same module where they are declared.╵",
+			explanation: "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\"",
+		},
+		{
+			errorOutput: " Error: Reference to undeclared input variable   on services/main.tf line 5, in module \"app\":    5:   environment = var.values.environment An input variable with the name \"values\" has not been declared.",
+			explanation: "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\"",
+		},
 	}
 
 	for _, tt := range testCases {
diff --git a/test/integration_stacks_test.go b/test/integration_stacks_test.go
index 18b45d2b..a894bb05 100644
--- a/test/integration_stacks_test.go
+++ b/test/integration_stacks_test.go
@@ -7,6 +7,8 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/gruntwork-io/terragrunt/shell"
+
 	"github.com/gruntwork-io/terratest/modules/files"
 
 	"github.com/gruntwork-io/terragrunt/config/hclparse"
@@ -1213,6 +1215,24 @@ func TestStacksNoValidation(t *testing.T) {
 	assert.Contains(t, stdout, "local_file.file will be created")
 }
 
+func TestStacksValuesError(t *testing.T) {
+	t.Parallel()
+
+	helpers.CleanupTerraformFolder(t, testFixtureStacksUnitValues)
+	tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStacksUnitValues)
+	rootPath := util.JoinPath(tmpEnvPath, testFixtureStacksUnitValues, "live")
+
+	_, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt stack generate --experiment stacks --non-interactive --working-dir "+rootPath)
+	require.NoError(t, err)
+
+	stackDir := util.JoinPath(rootPath, ".terragrunt-stack")
+	_, _, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt run-all apply --non-interactive --working-dir "+stackDir)
+	require.Error(t, err)
+
+	explanation := shell.ExplainError(err)
+	assert.Contains(t, explanation, "You are using a stacks feature without enabling it. Enable the stacks experiment through CLI flag \"--experiment stacks\".")
+}
+
 // check if the stack directory is created and contains files.
 func validateStackDir(t *testing.T, path string) {
 	t.Helper()