terragrunt icon indicating copy to clipboard operation
terragrunt copied to clipboard

Locals can not use dependency outputs

Open tomasbackman opened this issue 4 years ago • 11 comments

I have a terragrunt file with a dependecy block as normal.

dependency "stuff"  {
  config_path = "my_path"
}

The output I want to use is a nested object that require some massaging with a for loop to be usable

[for a in dependency.stuff.output.obj1["Thing"].names : dependency.stuff.output.obj2[a].id]

This works well when the above loop is used in the input block:

inputs {
  inp1 = [for a in dependency.stuff.output.obj1["Thing"].names : dependency.stuff.output.obj2[a].id]
}

But NOT if I try to make it a local first:

locals {
  variable_for_readability = [for a in dependency.stuff.output.obj1["Thing"].names : dependency.stuff.output.obj2[a].id]
}
inputs {
  inp1 = local.variable_for_readability
}

Then I get error message:

Not all locals could be evaluated: variable_for_readability Could not evaluate all locals in block. Unable to determine underlying exit code, so Terragrunt will exit with error code 1

I assume this is some bug and not by design? In any case it is annoying. Using versions: Terragrunt: 0.26.7 Terraform: 0.13.5 aws provider: 3.20.0

tomasbackman avatar Jan 14 '21 11:01 tomasbackman

This is currently by design, and is a limitation of the implementation (see configuration parsing order for more information). I could have sworn we already had a ticket for this, but it looks like that was just my imagination, so will keep this open until we figure out a way to overhaul the parsing mechanism to allow for this.

The main blocker here is having a maintainable, sane implementation of graph parsing of the terragrunt config.

yorinasub17 avatar Jan 14 '21 15:01 yorinasub17

Ah thx, I should have read (or remembered) that documentation earlier. It just took quite a while for me to pinpoint that it was due to the dependency being used in a local, and not the loop itself causing problems.. So meanwhile a new implementation is considered, maybe some improved error message could be added, like "dependencies cannot be used from local context" or similar.

tomasbackman avatar Jan 15 '21 09:01 tomasbackman

So meanwhile a new implementation is considered, maybe some improved error message could be added, like "dependencies cannot be used from local context" or similar.

This would be very helpful! I've stumbled into this problem multiple times and always waste some time debugging until I remember this fact.

abeluck avatar Apr 13 '21 10:04 abeluck

I've just stumbled into this! definitively something that'd make sense to add into the error message :)

kitos9112 avatar Jun 08 '21 21:06 kitos9112

I found myself with this same problem, the error message definitely needs to be improved to be more descriptive of the real issue.

xmsanchez avatar Sep 02 '21 08:09 xmsanchez

I found this issue as well!

However, I've found a workaround...janky but...

common_deps.hcl

dependency "my-stuff" {
    config_path = "../my-stuff"
}

terragrunt.hcl

locals {
    common_deps = read_terragrunt_config(find_in_parent_folders("common_deps.hcl"))
    var_name    = local.common_deps.dependency.my-stuff.outputs.name
}

I can't explain why this works, it just does.

TheBlackMini avatar Nov 02 '21 05:11 TheBlackMini

@TheBlackMini I believe this works as we have moved the dependency into another block. Locals are processed before dependencies. So you can't refer to a dependency in a local. But if we are refering to another block the entire block will be processed, so we can use the blocks output in a local.

https://terragrunt.gruntwork.io/docs/getting-started/configuration/#configuration-parsing-order

taliesins avatar Jun 29 '22 09:06 taliesins

Be advised that using dependency in read_terragrunt_config currently breaks the terragrunt run-all graph due to a technical limitation: https://github.com/gruntwork-io/terragrunt/issues/1128

So this works if you aren't using run-all, but will introduce another problem if you find yourself using run-all on a regular basis.

If you do need to depend on run-all, then unfortunately the safest way to reuse dependency outputs right now is by abusing inputs and exposed includes. I admit that it's not a very clean solution, but is the currently the only working one that respects all parameters including terragrunt run-all dependency graph.

See https://blog.gruntwork.io/even-more-dry-and-maintainable-code-with-terragrunt-5738d1ffc1c9#f9bc, specifically the example at the end of the section with _vpc_id.

yorinasub17 avatar Jun 29 '22 14:06 yorinasub17

any update?

debu99 avatar Sep 08 '23 15:09 debu99

any update? 👀

I faced the same issue. The error message is not clear about the configuration parsing order.


locals {
  route_table_ids = concat(dependency.vpc.outputs.private_route_table_ids, dependency.vpc.outputs.tgw_attach_route_table_ids)
}

inputs = {
  aws_routes = flatten([
    for rt in local.route_table_ids : {
      route_table_id          = rt
      destinations_cidr_block = ["10.0.0.0/8"]
      transit_gateway_id      = dependency.data_source.outputs.tgw_id
    }
  ])
}
ERRO[0000] Not all locals could be evaluated:            prefix=[/path/to/the/module/vpc-routes] 
ERRO[0000]      - route_table_ids [REASON: Can't evaluate expression at /path/to/the/module/vpc-routes/terragrunt.hcl:17,21-126: you can only reference other local variables here, but it looks like you're referencing something else (dependency is not defined)]  prefix=[/path/to/the/module/vpc-routes] 
ERRO[0000] Error processing module at '/path/to/the/module/vpc-routes/terragrunt.hcl'. How this module was found: Terragrunt config file found in a subdirectory of /path/to/the/module/vpc-routes. Underlying error: Could not evaluate all locals in block. 
ERRO[0000] Unable to determine underlying exit code, so Terragrunt will exit with error code 1

To fix this, I had to move the list of route table IDs within the input section.

inputs = {
  aws_routes = flatten([
    for rt in concat(dependency.vpc.outputs.private_route_table_ids, dependency.vpc.outputs.tgw_attach_route_table_ids) : {
      route_table_id          = rt
      destinations_cidr_block = ["10.0.0.0/8"]
      transit_gateway_id      = dependency.data_source.outputs.tgw_id
    }
  ])
}

thiagolsfortunato avatar Mar 18 '24 12:03 thiagolsfortunato