Skip to content

--queue-exclude-dir still parses excluded directories during dependency discovery, breaking explicit stack-based workflows #5124

@atmask

Description

@atmask

Describe the bug

When using Terragrunt stacks with template modules (i.e. gets generated into .terragrunt-stack/) that require stack context (e.g. usage of values.x in dependency block), --queue-exclude-dir does not prevent parsing of the excluded directories during dependency discovery. This causes parsing errors because template modules reference stack variables (like values) that are only available in the generated stack context.

Reproduction Steps

Expected Behavior:
--queue-exclude-dir '**/module/*' should completely exclude the module/ directory from both:

  • ✅ Execution queue (currently works)
  • ❌ Discovery/parsing phase (currently broken)

Actual Behavior:
The excluded directories are still parsed during dependency discovery, causing errors when template modules use stack-specific variables.

Reproduction Steps

Directory Structure:

infra/project-a/
├── terragrunt.stack.hcl               # Stack definition
├── staging.tfvars   # Stack values
└── module/
    └── terragrunt.hcl        # Template module (requires stack context)

Template module uses stack variables:

# module/terragrunt.hcl
dependency "project_b" {
  config_path = "${get_repo_root()}/project-b/.terragrunt-stack/${values.environment}"
}

Command

cd infra/project-a
terragrunt stack run plan --queue-exclude-dir '**/module/*'

Result:

22:48:05.344 DEBUG  Generating: staging (./module) to ./.terragrunt-stack/staging
22:48:05.348 DEBUG  Writing values file in ./.terragrunt-stack/staging
# Stack generation succeeds ✓
...
22:48:05.415 ERROR  Error: Unknown variable
22:48:05.416 ERROR    on ./module/terragrunt.hcl line 5, in dependency "project-b":
22:48:05.416 ERROR     5:   config_path = ".../${values.environment}"
22:48:05.416 ERROR  There is no variable named "values".

Evidence from Trace Logs:
The stack trace shows this occurs during discovery phase in internal/discovery/discovery.go:

github.com/gruntwork-io/terragrunt/internal/discovery/discovery.go:515
github.com/gruntwork-io/terragrunt/internal/discovery/discovery.go:878
github.com/gruntwork-io/terragrunt/internal/discovery/discovery.go:834
github.com/gruntwork-io/terragrunt/config/config_partial.go:444
github.com/gruntwork-io/terragrunt/config/config_partial.go:318
github.com/gruntwork-io/terragrunt/config/config_partial.go:296
github.com/gruntwork-io/terragrunt/internal/discovery/discovery.go:515github.com/gruntwork-io/terragrunt/internal/discovery/discovery.go:878github.com/gruntwork-io/terragrunt/internal/discovery/discovery.go:834github.com/gruntwork-io/terragrunt/config/config_partial.go:444github.com/gruntwork-io/terragrunt/config/config_partial.go:318github.com/gruntwork-io/terragrunt/config/config_partial.go:296

The discovery phase attempts to parse ./module/terragrunt.hcl as a standalone unit, despite it being excluded via --queue-exclude-dir.

Comparison: Why --queue-include-dir & --queue-strict-include Works

Using --queue-strict-include --queue-include-dir '**/.terragrunt-stack/**/*' works correctly because it prevents discovery from scanning module/ entirely:

22:49:10.487 DEBUG  Generating: staging (./module/regional) to ./.terragrunt-stack/staging
22:49:10.505 DEBUG  [Partial] Included config ../../../root.hcl has strategy shallow merge
# No attempt to parse ./module/terragrunt.hcl ✓
22:49:10.487 DEBUG  Generating: staging (./module) to ./.terragrunt-stack/staging
22:49:10.505 DEBUG  [Partial] Included config ../../../root.hcl has strategy shallow merge
# No attempt to parse ./module/regional/terragrunt.hcl ✓

Versions

Terragrunt Version: 0.91.5
Tofu Version: 1.10.6
OS: macOS (darwin 24.5.0)

Additional Notes

builder.go has the following:


	// NOTE: We do NOT pass ExcludeDirs to discovery because excluded units need to be
	// discovered and reported (for --report-file functionality). The unit resolver will
	// handle exclusions after discovery, ensuring excluded units appear in reports.
	//
	// For now... We can probably use the following once runnerpool has been updated to not expect external
	// dependencies in the discovery results.
	//
	// if !terragruntOptions.IgnoreExternalDependencies {
	// 	d = d.WithDiscoverExternalDependencies()
	// }

	// Pass include behavior flags
	if terragruntOptions.StrictInclude {
		d = d.WithStrictInclude()
	}

It seems this is intentional but has this side effect. I would imaging we could find a way to still achieve the reporting without needing to parse the excluded dir

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions