How can I fix inconsistent conditional result types when returning values from the same map?

I have a map of values, and I’m basically trying to replace a number of different values while in a giant loop.

I’ve gotten so far, and feel like I’ve almost got this working but stumbling at what maybe the final step.

 Error: Inconsistent conditional result types
│ 
│   on main.tf line 25, in locals:
│   25:       source_ranges = distinct(flatten([for source in [for source in v.source_ranges_names : source == "#Env" ? replace(source, "#Env", env) : (length(regexall("#Env_customer_cidr", source)) > 0 && env == "prod" ? local.defined_ranges["prod_customer_cidr"] : (length(regexall("#Env_customer_cidr", source)) > 0 && env == "test" ? local.defined_ranges["test_customer_cidr"] : local.defined_ranges[source] ))]: local.defined_ranges[source] ]))
│     ├────────────────
│     │ local.defined_ranges is object with 18 attributes
│     │ local.defined_ranges["prod_customer_cidr"] is tuple with 1 element
│     │ local.defined_ranges["test_customer_cidr"] is tuple with 1 element
│ 
│ The true and false result expressions must have consistent types. The given
│ expressions are string and list of string, respectively.

I don’t understand the cause of the error, as I’m referring back to the same object each time and the values in the object are all defined the same way:

   "defined_ranges": {
        "random_cidr": [
            "192.168.1.0/24"
        ],
        "prod_customer_cidr": [
            "192.168.2.0/24"
        ],
        "test_customer_cidr": [
            "192.168.3.0/24"
        ],
    }

In the example error above, source would have a value such as ‘random_cidr’.

I realise this can likely be refactored into something far easier to read/understand but I’m still getting my head around what the terraform is doing.

Hi @djsmiley2k,

First I’m going to reformat your expression a little so it’s a little easier for me to see what all the parts are:

  source_ranges = distinct(
    flatten([
      for source in [
        for source in v.source_ranges_names : (
          source == "#Env" ?
          replace(source, "#Env", env) :
          (
            length(regexall("#Env_customer_cidr", source)) > 0 && env == "prod" ?
            local.defined_ranges["prod_customer_cidr"] :
            (
              length(regexall("#Env_customer_cidr", source)) > 0 && env == "test" ?
              local.defined_ranges["test_customer_cidr"] :
              local.defined_ranges[source]
            )
          )
        ] : local.defined_ranges[source]
      ])
    )

Unfortunately Terraform’s highlighting of the relevant part of the source snippet doesn’t survive pasting into the forum here so I can’t tell definitively which of the expressions Terraform was talking about, but looking at each of them in turn the outermost one seems to be consistent with what the error message reported:

  • replace(source, "#Env", env) returns a string
  • your other condition “arm” returns one of the elements of local.defined_ranges, all of which are lists of string

I’m having to guess a little what your goal was with this expression but perhaps you intended to make that first expression also be a lookup in the local value:

local.defined_ranges[replace(source, "#Env", env)]

As you noted, I think there are some opportunities to simplify and clarify this, but I tried to focus on explaining the specific error you mentioned here, since you said that was specifically what you were interested in.

If you do want to simplify from here though, my general advice would be to not be afraid to use more than one local value to break the problem down into multiple smaller steps. For example, it might help to factor out the special case of source being "#Env" as an expression of its own, so that your other expression can just assume it already has a fully-resolved “source” and make a decision based on it. Using a map as a lookup table can also often be a good alternative to having a bunch of nested conditional expressions all testing the same value.

1 Like

Hi @apparentlymart,

I’ve since moved on from this issue with a rather bodgy work around, but I am going to come back and see if what you’ve pointed out works for me (and I’m going to try using a join() on those lists of strings, as that maybe my solution here).

Thanks for your help and comments, I think they are lending me at least greater understanding of what’s going on :slight_smile:

Part of the issue is I’m unsure how much information I can share on a public forum, and so I have to sanitize everything first while trying to make sure I don’t miss any vital information. I think maybe we’re approaching the substitution completely wrong, but it just happens we had a solution very similar to this, which we’ve needed to extend for more variables.