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.
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.
Let’s now take a look at some limitations and best practices for the Terraform try
function:
try
should be used when you don’t know if the data will exist or how it is going to be formed.- 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. - Although
try
can technically accept any sort of expression it is recommended to use it only with simple attribute references and type conversion functions. - 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.
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 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.
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:
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."
}
}
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.