Terraform check and precondition Generator

Generate the three kinds of assertion Terraform has. Choosing between them comes down to one question, and most people get the answer backwards.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Generate. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

Assertions for a resource

The generated skeleton marks which condition can use self and which cannot

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
}

A data source

Data sources take conditions too, and one inside a check block fails softly

data "aws_ami" "ubuntu" {
  most_recent = true
}

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Using a check block to stop a bad apply

    A failed check is a warning. The apply proceeds, so the guard exists, reports the problem, and changes nothing about the outcome.

    Instead:Use a precondition or a postcondition when the run must stop. Keep check blocks for what you want reported.

  2. Referring to self in a precondition

    It runs before the object exists, so there is nothing for self to refer to, and using the resource's own address instead is a dependency cycle.

    Instead:Check inputs and other resources in a precondition; check the result in a postcondition through self.

  3. Writing a generic error_message

    Terraform prints the message and the address and nothing else, so a message without the offending value leaves the reader to work out what happened from the configuration.

    Instead:Interpolate the value: "Expected at least two subnets, got ${length(var.subnets)}."

A check block warns. A precondition stops.

Almost everybody adding their first check block expects it to be a gate. It is a monitor: the assertion fails, a warning appears, and the apply succeeds.

check is a monitor, not a gate

Its assert produces a warning in the output and stops nothing. That is useful for something you want reported and are willing to proceed past, such as an endpoint that should be healthy. Used as a guard, the guard is there and does nothing, which is worse than no guard because everybody believes it.

precondition and postcondition fail the operation

These live inside a resource's lifecycle block and they do stop the run. A precondition is evaluated before Terraform creates or changes the object, so it can prevent the work. A postcondition runs after and checks the result.

self exists in a postcondition and not in a precondition

The precondition runs before the object exists, so there is nothing to look at, and referring to the resource by its own address is a dependency cycle. In a postcondition, self.attribute is how you check what was actually created.

A data source inside a check block is scoped to it

And its failure produces a warning rather than failing the plan. That is the reason to put a probe there rather than at the top level: an ordinary data source that cannot be read fails the plan, which is exactly what you do not want from something reaching out to the network.

error_message is the only thing the reader gets

Terraform prints the message and the address and nothing about the values, unless you interpolate them yourself. "Invalid configuration" tells somebody at three in the morning nothing at all; "Expected at least two subnets, got 1" tells them everything.

Preconditions arrived in 1.2 and check blocks in 1.5

On an older version each is reported as an unsupported block, naming the block rather than the version. Setting required_version turns that into a message about the version instead.

More terraform tools

Terraform Validator & Formatter Does it parse, and is it formatted? Terraform dynamic Block Generator It is ingress.value, not each.value Terraform variables.tf Generator From the var. references you already wrote Terraform Unused Declaration Linter Dead variables, locals and data sources Terraform Atlantis YAML Generator when_modified misses your modules Terraform Function Tester and HCL Console terraform console, in a tab Terraform for Expression Tester Where do the keys collide? Terraform Interpolation Tester null becomes an empty string Terraform templatefile Tester Render it before you apply it Terraform Resource Count Calculator How many objects, not how many blocks Terraform count to for_each Converter With the moved blocks it needs Terraform moved Block Generator Rename without destroying Terraform state mv Command Builder No plan, no undo Terraform target Flag Builder And why to stop using it Terraform outputs.tf Generator Outputs are not sensitive by default Terraform Remote State Data Source Generator It grants read of the whole state Terraform Provider Block Generator docker is not hashicorp/docker Terraform .gitignore Generator and Checker .terraform* eats the lock file Terraform to OpenTofu Migration Checker The state is the part to watch Terraform tfvars to JSON Converter The JSON file wins Terraform Version Constraint Parser What ~> actually allows Terraform Resource Address Parser Quote it before the shell eats it Terraform cidrsubnet Calculator newbits is added, not the target Terraform Import Block Generator The id is not the name Terraform Lock File Viewer Why CI fails and your laptop does not Terraform Variables Checker A missing value hangs CI Terraform tfvars to Env Vars Converter Lists and maps have to be JSON Terraform Deprecated Syntax Checker What a current Terraform rejects Terraform State File Viewer Read it without uploading it Terraform Plan JSON Viewer It is not redacted Terraform HCL to JSON Converter And what the conversion loses Terraform Module Source Validator version only works for the registry Terraform Backend Config Decoder Is state actually locked? Terraform Naming Convention Validator A hyphen makes a resource unreferenceable

Elsewhere on the site