Repository: gruntwork-io/terragrunt (language: go)

Issue:
SIGSEGV when using include and find_in_parent_folders
## Describe the bug

I've created a directory tree to manage Grafana IaC that is setup like this:

```
systems
├── account-card
│   ├── eng_teams.hcl
│   ├── prod
│   │   ├── <app>
│   └── qa
│       ├── <app>
```

Each <app> sub directory has it's own `terragrunt.hcl` file, which will do the actual work.

This structure started with plain Terraform, so there are still tfvars files that I'm trying to replace with the combination of a HCL file, `include` and the `find_in_parent_folders` function.

I can reference `eng_teams.hcl` like this:

```hcl
include {
  path = find_in_parent_folders("eng_teams.hcl")
}
```

And it works as expect. But if I want to use another HCL right under `systems` directory, I get the following error:

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1aa296d]

goroutine 9 [running]:
github.com/gruntwork-io/terragrunt/config.PartialParseConfig(0xc000b1dc80, 0xc001333300, 0x0)
	/home/circleci/project/config/config_partial.go:389 +0x3cd
github.com/gruntwork-io/terragrunt/config.TerragruntConfigFromPartialConfig(0xc000b1dc80, 0xc001333300, 0x0)
	/home/circleci/project/config/config_partial.go:326 +0x3c5
github.com/gruntwork-io/terragrunt/config.PartialParseConfigFile(0xc000b1dc80, {0xc000b163f0, 0x69}, 0x0)
	/home/circleci/project/config/config_partial.go:304 +0x1e6
github.com/gruntwork-io/terragrunt/cli/commands/run.getTerragruntConfig({0x2f44ce8, 0xc0012ddd40}, 0xc000bde008)
	/home/circleci/project/cli/commands/run/run.go:916 +0x105
github.com/gruntwork-io/terragrunt/cli/commands/run.CheckVersionConstraints({0x2f44ce8, 0xc0012ddd40}, 0xc000bde008)
	/home/circleci/project/cli/commands/run/version_check.go:37 +0x2f
github.com/gruntwork-io/terragrunt/cli/commands/run.run({0x2f44ce8, 0xc0012ddd40}, 0xc000bde008, 0xc00137bde8)
	/home/circleci/project/cli/commands/run/run.go:106 +0x186
github.com/gruntwork-io/terragrunt/cli/commands/run.Run({0x2f44ce8?, 0xc0012ddd40?}, 0xc0012eb6d0?)
	/home/circleci/project/cli/commands/run/run.go:88 +0x56
github.com/gruntwork-io/terragrunt/cli/commands/run.NewSubcommands.func1.Action.1(0xc0012eb6d0)
	/home/circleci/project/cli/commands/run/cli.go:82 +0x9c
github.com/gruntwork-io/terragrunt/cli/commands/run.NewSubcommands.func1(0x0?)
	/home/circleci/project/cli/commands/run/cli.go:63 +0x2f
github.com/gruntwork-io/terragrunt/cli/commands/common/runall.WrapCommand.func1(0x0?, 0x0?)
	/home/circleci/project/cli/commands/common/runall/cli.go:45 +0xcd
github.com/gruntwork-io/terragrunt/internal/cli.(*Command).WrapAction.func1(0x0?)
	/home/circleci/project/internal/cli/command.go:292 +0x1b
github.com/gruntwork-io/terragrunt/cli/commands/common/graph.WrapCommand.func1(0x0?, 0x0?)
	/home/circleci/project/cli/commands/common/graph/cli.go:40 +0xcd
github.com/gruntwork-io/terragrunt/internal/cli.(*Command).WrapAction.func1(0x0?)
	/home/circleci/project/internal/cli/command.go:292 +0x1b
github.com/gruntwork-io/terragrunt/cli/commands.NewShortcutsCommands.func1(0x0?)
	/home/circleci/project/cli/commands/shortcuts.go:64 +0x82
github.com/gruntwork-io/terragrunt/cli.runAction.func2()
	/home/circleci/project/cli/app.go:224 +0x47
golang.org/x/sync/errgroup.(*Group).Go.func1()
	/home/circleci/go/pkg/mod/golang.org/x/sync@v0.12.0/errgroup/errgroup.go:78 +0x50
created by golang.org/x/sync/errgroup.(*Group).Go in goroutine 1
	/home/circleci/go/pkg/mod/golang.org/x/sync@v0.12.0/errgroup/errgroup.go:75 +0x96
```

It doesn't matter the filename or the content (even if it's empty) I'm using, the result is the same.

This is the line that I'm using to reference this "global" configuration:

```hcl
include {
  path = find_in_parent_folders("_envcommon.hcl")
}
```

Once commented out or removed, the unit works as expected.

Interesting fact is that I have a tfvars (which I'm trying to replace) at the same level of `systems` and it works as expected too:

```hcl
locals {
  environment = jsondecode(read_tfvars_file("../../../../environments.tfvars.json"))
}

inputs = merge(
  { environment = basename(dirname(get_terragrunt_dir())),
    app = {
      "kind"      = "deployment",
      "namespace" = "foobar",
      "slug"      = "barfoo"
    }
  },
  local.environment
)
```

## Steps To Reproduce

1. Create the directory tree
2. Create a unit configuration at the application level
3. Create the `eng_teams.hcl` at the system level. The file only defines an `input` block.
4. Create the `_envcommon.hcl` file right under `systems`
5. Move to the application sub directory (where the unit is) and run `terragrunt plan` or `terragrunt apply`.

```hcl
terraform {
  source = "../../../../base"
}

locals {
  teams       = jsondecode(read_tfvars_file("../../../../teams.tfvars"))
  // the line below should replaced by the include of _envcommon.hcl
  environment = jsondecode(read_tfvars_file("../../../../environments.tfvars.json"))
}

include {
  path = find_in_parent_folders("eng_teams.hcl")
}

// if the line below is removed, everything works fine
include {
  path = find_in_parent_folders("_envcommon.hcl")
}

inputs = merge(
  { environment = basename(dirname(get_terragrunt_dir())),
    app = {
      "kind"      = "deployment",
      "namespace" = "foobar",
      "slug"      = "barfoo"
    }
  },
  local.teams,
  local.environment
)
```

## Expected behavior

The selected operation from terragrunt should be executed without errors, and the shared configuration can be used all other application unit's.

## Nice to haves

- [X] Terminal output
- [ ] Screenshots

## Versions

- Terragrunt version: v0.77.22
- Terraform version: v1.11.3
- Environment details: Ubuntu 22.04.5 LTS

## Additional context

`base` modules providers:

```hcl
terraform {
  required_providers {
    grafana = {
      source  = "grafana/grafana"
      version = "3.22.2"
    }
    http = {
      source  = "hashicorp/http"
      version = "3.4.5"
    }
  }
}

provider "grafana" {
  url  = "https://${var.environments.servers[var.environment]}"
  auth = var.grafana_token
}
```

Inside this module, several of modules are included with `module` blocks, all of them using relative paths in the file system.



Discussion / hints:
Thanks for reporting this, @afreitas5 . We'll take a look soon.

Fix patch:
diff --git a/config/config.go b/config/config.go
index 61206fcc80..2c63db0efe 100644
--- a/config/config.go
+++ b/config/config.go
@@ -1288,9 +1288,11 @@ func ParseConfig(ctx *ParsingContext, file *hclparse.File, includeFromChild *Inc
 		errs = errs.Append(err)
 	}
 
-	ctx = ctx.WithTrackInclude(baseBlocks.TrackInclude)
-	ctx = ctx.WithFeatures(baseBlocks.FeatureFlags)
-	ctx = ctx.WithLocals(baseBlocks.Locals)
+	if baseBlocks != nil {
+		ctx = ctx.WithTrackInclude(baseBlocks.TrackInclude)
+		ctx = ctx.WithFeatures(baseBlocks.FeatureFlags)
+		ctx = ctx.WithLocals(baseBlocks.Locals)
+	}
 
 	if ctx.DecodedDependencies == nil {
 		// Decode just the `dependency` blocks, retrieving the outputs from the target terragrunt config in the
diff --git a/config/config_partial.go b/config/config_partial.go
index 48cd12f5d4..b0c0180972 100644
--- a/config/config_partial.go
+++ b/config/config_partial.go
@@ -383,9 +383,11 @@ func PartialParseConfig(ctx *ParsingContext, file *hclparse.File, includeFromChi
 		errs = errs.Append(err)
 	}
 
-	ctx = ctx.WithTrackInclude(baseBlocks.TrackInclude)
-	ctx = ctx.WithFeatures(baseBlocks.FeatureFlags)
-	ctx = ctx.WithLocals(baseBlocks.Locals)
+	if baseBlocks != nil {
+		ctx = ctx.WithTrackInclude(baseBlocks.TrackInclude)
+		ctx = ctx.WithFeatures(baseBlocks.FeatureFlags)
+		ctx = ctx.WithLocals(baseBlocks.Locals)
+	}
 
 	// Set parsed Locals on the parsed config
 	output, err := convertToTerragruntConfig(ctx, file.ConfigPath, &terragruntConfigFile{})


Test patch:
diff --git a/test/fixtures/regressions/include-error/_envcommon.hcl b/test/fixtures/regressions/include-error/_envcommon.hcl
new file mode 100644
index 0000000000..eeee7a4b14
--- /dev/null
+++ b/test/fixtures/regressions/include-error/_envcommon.hcl
@@ -0,0 +1,4 @@
+
+inputs = {
+  common_config = "Common Config"
+}
diff --git a/test/fixtures/regressions/include-error/project/app/terragrunt.hcl b/test/fixtures/regressions/include-error/project/app/terragrunt.hcl
new file mode 100644
index 0000000000..bd6015beff
--- /dev/null
+++ b/test/fixtures/regressions/include-error/project/app/terragrunt.hcl
@@ -0,0 +1,17 @@
+
+include {
+  path = find_in_parent_folders("eng_teams.hcl")
+}
+
+include {
+  path = find_in_parent_folders("_envcommon.hcl")
+}
+
+inputs = {
+  app = {
+    "kind"      = "deployment",
+    "namespace" = "foobar",
+    "slug"      = "bar-foo",
+    "data"      = "46521694",
+  }
+}
diff --git a/test/fixtures/regressions/include-error/project/eng_teams.hcl b/test/fixtures/regressions/include-error/project/eng_teams.hcl
new file mode 100644
index 0000000000..6b9b6d89eb
--- /dev/null
+++ b/test/fixtures/regressions/include-error/project/eng_teams.hcl
@@ -0,0 +1,4 @@
+
+inputs = {
+  team_name = "Test Team"
+}
diff --git a/test/integration_regressions_test.go b/test/integration_regressions_test.go
index ab774d2bc0..c57dd50099 100644
--- a/test/integration_regressions_test.go
+++ b/test/integration_regressions_test.go
@@ -85,3 +85,15 @@ func TestMockOutputsMergeWithState(t *testing.T) {
 	helpers.LogBufferContentsLineByLine(t, stdout, "shallow-map-executed")
 	require.NoError(t, err)
 }
+
+func TestIncludeError(t *testing.T) {
+	t.Parallel()
+
+	helpers.CleanupTerraformFolder(t, testFixtureRegressions)
+	tmpEnvPath := helpers.CopyEnvironment(t, testFixtureRegressions)
+	rootPath := util.JoinPath(tmpEnvPath, testFixtureRegressions, "include-error", "project", "app")
+
+	_, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --terragrunt-non-interactive --terragrunt-working-dir "+rootPath)
+	require.Error(t, err)
+	assert.Contains(t, err.Error(), "include blocks without label")
+}