Going to AWS re:Invent 2024?

➡️ Book a meeting with Spacelift

Terraform

How to Use Terraform Try & Can Functions [Examples]

How to Use Terraform Try

In this article, we will take a look at some useful built-in functions you should know about in Terraform, try and can, introduced to Terraform from version 12.20. We will explain what they are, and what they are used for, as well as run through some examples to show their usage. We will then describe how they compare to the lookup function.

  1. What does try function do in Terraform?
  2. Terraform try limitations and best practices
  3. Using Terraform try – example
  4. Terraform try vs lookup
  5. What is Terraform can function?
  6. Using Terraform can – examples

What does try function do in Terraform?

Terraform try evaluates all of its argument expressions in turn and returns the result of the first one that does not produce any errors. The try function can only catch and handle dynamic errors resulting from access to data that isn’t known until runtime. The try function is intended only for concise testing of the presence of and types of object attributes. It can technically accept any sort of expression.

How to use Terraform try?

 

try(value, default)
  • value: The value to look up in the map.
  • default: The value to return if the key is not found in the map.

Example:

locals {
 jedi_map = {
   darth = "sith"
 }
 try1 = try(local.jedi_map.boba_fett, "jedi")
}

output "try1" {
 value = local.try1
}

The output of this code will be “jedi”, as the expression local.map_var.boba_fett has not been declared.

If the value of the try function used to evaluate the condition does not exist, then it will error. In the below example, local.nothing.here is not declared in my configuration, and so the condition produces an error. It will not catch errors relating to expressions that can be proven to be invalid for any input, such as a malformed resource reference.

try function terraform

Terraform try limitations and best practices

Let’s now take a look at some limitations and best practices for the Terraform try function:

  1. try should be used when you don’t know if the data will exist or how it is going to be formed.
  2. Hashicorp recommends to use the try function only in special local values whose expressions perform normalization. To make sure that the error handling is confined to a single location in the module and the rest of the module can just use straightforward references to the normalized structure and thus be more readable for future maintainers.
  3. Although trycan technically accept any sort of expression it is recommended to use it only with simple attribute references and type conversion functions.
  4. Always try to keep your code simple to promote readability. Overuse of try to suppress errors will lead to a configuration that is hard to understand and maintain.

Check out other Terraform best practices to improve your Terraform workflow.

Using Terraform try — examples

In this example, we use the try function to check if a map of Kubernetes namespaces exists, if not, then it uses the default.

 config = {
    namespaces = ["namespace_jedi", "namespace_sith"]

    (...)
  }

resource "kubernetes_namespace" "ns" {
  for_each = var.config.namespaces

  (...)

resource "kubernetes_namespace" "ns" {
  for_each = try(var.config.namespaces, ["namespace_jedi", "namespace_sith"])

  (...)

In the next example, try is used to deal with situations where a value might be provided in two different forms, allowing us to normalize to the most general form.

The variable accepts any type and the try function then uses the tostring and tolist expressions to try a conversion to a string or a list.

variable "jedi_list" {
  type = any
}

locals {
  example = try(
    [tostring(var.jedi_list)],
    tolist(var.jedi_list),
  )
}

In the last example, we show how multiple values can be tested using the try function. A locals map is specified with a key value pair of luke = "jedi" — we then test for two unspecified values, before the third one will be used as it exists. The code below outputs jedi .

locals {
  jedi = {
    luke = "jedi"
  }
}

output "try" {
  value = try(local.jedi.bar, local.jedi.baz, local.jedi.luke, "not_a_jedi")
}

Terraform try vs lookup

Terraform try is a more general form of the lookup function in Terraform. The lookup function is used to retrieve the value of a map element or list element.

Usage:

lookup(map, key, [default])
  • map: The map from which to look up the value.
  • key: The key to look up in the map.
  • default (optional): The value to return if the key is not found in the map. If not specified and the key is not found, null is returned.

Terraform lookup example:

variable "jedi_map" {
  type    = map(string)
  default = {
    luke  = "jedi",
    darth = "sith",
  }
}

output "result" {
  value = lookup(var.jedi_map, "luke", "sith")
}

In this example, lookup is used to retrieve the value associated with the key “luke” from the map var.jedi_map. If the key is not found, it returns the default value “sith”. In this case, it will be found and return “jedi”.

See also Terraform try vs coalesce function.

What is Terraform can function?

The Terraform can function tries evaluating an expression and returns a boolean value indicating whether it succeeded.

How to use Terraform can?

Let’s look at an example.

> local.jedi
{
  "yoda" = "jedi"
}
> can(local.jedi.yoda)
true
> can(local.jedi.darth)
false

In this example, a local map is declared with the key of “yoda” and the value of “jedi”. The can function is used to test if the value exists, and returns true if it does, and false if it does not.

Similar to the try function, if the value is not declared, then an error message will be produced:

terraform lookup vs try

Using Terraform can — example

The example below shows how to use the can function in variable validation to ensure a timestamp is valid. The condition will fail if the second argument is not a valid timestamp, using the formatdate function.

variable "timestamp" {
  type        = string

  validation {
    condition     = can(formatdate("", var.timestamp))
    error_message = "The timestamp is invalid."
  }
}

Key points

In summary Terraform try evaluates all of its argument expressions in turn and returns the result of the first one that does not produce any errors and can evaluates the given expression and returns a boolean value indicating whether the expression produced a result without any errors.

We encourage you also to explore how Spacelift makes it easy to work with Terraform. If you need any help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this. If you want to learn more, create a free account today or book a demo with one of our engineers.

Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.

Manage Terraform Better with Spacelift

Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.

Start free trial

The Practitioner’s Guide to Scaling Infrastructure as Code

Transform your IaC management to scale

securely, efficiently, and productively

into the future.

ebook global banner
Share your data and download the guide