Nested For Loops

When I run this code:

locals {
  workflows1 = split(";",var.workflows)
  environment_type = upper(strrev(substr(strrev(var.environment),0,5)))
  json_files1 = (var.environment_type == "QUERY" ? fileset(path.module, "../../../../workflows/bigquery.json"):
  [for wf in local.workflows1: [
  [ for fn in fileset(path.module,wf): fn if upper(strrev(substr(strrev(fn),5,5))) != "QUERY"]
  json_files = concat(var.json_files, [var.json_files1])

I get this error:

Error: Inconsistent conditional result types

  on line 18, in locals:
  18:   json_files1 = (var.environment_type == "QUERY" ? fileset(path.module, "../../../../workflows/bigquery.json"):
  19:   [for wf in local.workflows1: [
  20:   [ for fn in fileset(path.module,join("","../../../../workflows/",wf,".json")): fn if upper(strrev(substr(strrev(fn),5,5))) != "QUERY"]
  21:   ]])
    | local.workflows1 is list of string with 1 element
    | path.module is "."
    | var.environment_type is null

The true and false result expressions must have consistent types. The given
expressions are set of string and tuple, respectively

Please help if you can.

The error “Inconsistent conditional result types” is caused by the conditional expression in your Terraform code having branches that return values of different types. The true branch returns a set of strings from a fileset() function, whereas the false branch, due to the nested for loops, produces a list of lists of strings. Terraform requires both branches of a conditional expression to produce the same type of result for consistency.

Indeed! Let’s first reformat this a little so it’s easier to see from the indentation how things are nested:

  json_files1 = (
    var.environment_type == "QUERY" ?
    fileset(path.module, "../../../../workflows/bigquery.json") :
      for wf in local.workflows1 : [
        for fn in fileset(path.module, wf) : fn
        if upper(strrev(substr(strrev(fn),5,5))) != "QUERY"

As @rtwolfe said, the first result of the conditional is just the fileset result, which is always a set(string) value. The second result is built from two levels of [ for ... ] expression nesting, which means the result will be of type shaped roughly like tuple([tuple([ ... ]), ...]), where the ... placeholders depend on how many results each of the for expressions produce.

There are two changes required to make these result types consistent: to flatten the second result into a tuple with just strings inside it, and then to convert that tuple to a set:

      for wf in local.workflows1 : [
        for fn in fileset(path.module, wf) : fn
        if upper(strrev(substr(strrev(fn),5,5))) != "QUERY"

All I’ve done here is wrap the original expression in toset(flatten(...)). This should then produce a set(string) result, and so will match with the result type of the first conditional result.