4.3 Validate a Configuration

Key Takeaways

  • terraform validate checks that configuration is syntactically valid and internally consistent: attributes, required arguments, and types it can see from provider schemas
  • validate does not call cloud APIs and does not check whether a VPC ID, AMI, or other remote object actually exists
  • terraform fmt is style only; terraform plan refreshes remote objects and proposes actions — neither is a substitute for the other
  • Validation requires an initialized working directory (providers and modules installed); terraform init -backend=false is the official way to init for validate-only CI
  • Custom conditions (objective 4g) can make validate fail; treat that as a mention, not the whole condition system
Last updated: August 2026

4.3 Validate a Configuration

Quick Answer: terraform validate checks that the configuration is syntactically valid and internally consistent. It uses installed provider schemas to catch bad argument names, missing required arguments, and type errors it can see without credentials. It does not call AWS or Azure to ask whether vpc-0abc123 exists. That check is plan. fmt only rewrites style.

Objective 3c on Terraform Associate (004) is terraform validate on Terraform 1.12. HashiCorp's command reference opens with the sentence you should be able to repeat: the command validates configuration files in a directory and does not validate remote services, such as remote state or provider APIs.

Official references: terraform validate command, terraform fmt command, and the language style guide (run fmt and validate before you commit).

Why this objective appears on 004

Candidates collapse three commands into one vague "check my code." 004 separates them on purpose:

  • Style is fmt.
  • Internal consistency is validate.
  • What would change in the real account is plan.

If you claim validate proves the VPC ID is real, you are describing plan (and even plan only proves the provider's read succeeded at that moment). If you claim fmt catches a missing ami argument, you are describing validate.

What terraform validate checks

Usage: terraform validate [options].

After a successful init, validate loads the root module, the installed child modules, and the provider schemas those plugins expose. It then asks: is this configuration a legal Terraform program?

Typical failures validate can see:

  • HCL syntax errors (unclosed brace, bad interpolation).
  • A resource type the installed provider does not implement.
  • An argument name that is not in the schema (ami_id on aws_instance instead of ami).
  • A required argument the schema says is missing.
  • An obvious type problem (count = "three" when a number is required).
  • References to names that do not exist in this configuration (var.missing, aws_instance.nope.id).
  • Some author-written custom conditions, when Terraform can evaluate them from configuration alone (objective 4g — mentioned below, not taught here).

Typical questions validate cannot answer:

  • Does vpc-0abc123 exist in this AWS account?
  • Are these credentials valid?
  • Is the remote state file reachable?
  • Will the provider API accept this combination of arguments at apply time?
  • Is the live infrastructure drifted from state?

HashiCorp's introduction is explicit: validate verifies that a configuration is syntactically valid and internally consistent, regardless of any provided variables or existing state. It is aimed at reusable modules and editor/CI checks. To verify a configuration in the context of a particular run (this workspace, these variable values, this state), use terraform plan, which includes an implied validation check and then talks to the world.

resource "aws_instance" "web" {
  # validate fails: "ami_id" is not an aws_instance argument
  ami_id        = "ami-0123456789abcdef0"
  instance_type = "t3.micro"
  subnet_id     = "subnet-0abc123" # validate accepts the type; it does not look up the subnet
}

Fix the argument name and validate can succeed even if that AMI and subnet were deleted yesterday. Only plan (refresh + provider reads) discovers the missing remote objects.

$ terraform validate
Success! The configuration is valid.

You normally run it after init

Validation requires an initialized working directory with referenced plugins and modules installed. Provider schemas live in those plugins. Without init, validate cannot know whether ami is required on aws_instance.

HashiCorp's documented pattern for CI that should validate without touching remote state:

terraform init -backend=false
terraform validate

-backend=false still installs providers and modules. Use it when the working directory was already designed to init, or when you only need schemas. Do not treat it as a substitute for a real init on the apply path.

The official init tutorial places validate immediately after the first successful init, before you inspect .terraform/. That is the habit 004 wants: Write → Init → Validate → Plan → Apply.

Contrast: fmt, validate, and plan

CommandQuestion it answersTalks to cloud APIs?Needs init?Changes files or infrastructure?
terraform fmtDoes this HCL match canonical style?NoNoRewrites .tf files (unless -check / -write=false)
terraform validateIs this configuration internally consistent?NoYes (plugins + modules)No
terraform planWhat would change if we applied, given current state and remote objects?Yes (refresh / reads)YesUpdates state only if you later apply; plan itself proposes

fmt is style only

terraform fmt rewrites configuration to HashiCorp's canonical format: indentation, argument alignment, a subset of the language style guide. It is intentionally opinionated and has no style-rule flags. Useful flags on 004:

  • -check — exit non-zero if files are not formatted (CI).
  • -diff — show the formatting diff.
  • -recursive — include subdirectories (modules).
  • -write=false — do not overwrite.

fmt will not tell you that ami is missing. A perfectly formatted file can still be invalid. Objective 3g covers formatting in more depth; here you only need the contrast: fmt does not validate.

plan is refresh plus proposed actions

terraform plan performs the default planning operations from 4.1: read remote objects, compare configuration to state, propose create/update/destroy. It also runs an implied validate first. A configuration that fails validate never becomes a meaningful plan. The reverse is not true: validate can pass and plan can still fail on a missing VPC, bad credentials, or a custom condition that needs remote data.

Use this decision list on the exam:

  • Whitespace and argument alignment → fmt
  • Wrong argument name or missing required argument → validate
  • "Will this create two instances or destroy the bucket?" → plan
  • "Does this ID exist in the account?" → plan (not validate)

Machine-readable output: -json

terraform validate -json prints a JSON object for editors and CI. Official fields include:

  • valid (boolean)
  • error_count / warning_count
  • diagnostics — each item has severity (error or warning), summary, optional detail, and optional source range

Warnings do not make valid false. Errors do. External tools must tolerate non-JSON on stdout if Terraform fails before validation starts. You do not need to memorize the snippet schema for 004; you do need to know -json exists and that it is for automation, not for humans at a terminal.

Custom conditions can make validate fail (objective 4g is later)

Terraform 1.12 includes author-written checks: variable validation blocks, precondition / postcondition on resources, data sources, and outputs, and check blocks. Objective 4g teaches that system. For 3c, remember one sentence: a custom condition that validate can evaluate from configuration may cause terraform validate to fail, even though the HCL is otherwise well-formed.

variable "environment" {
  type = string

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "environment must be dev, staging, or prod."
  }
}

If that condition is evaluable during validate and it fails, validate reports an error. That still is not a cloud lookup. A precondition that reads data.aws_ami.example.architecture needs a plan-time read; it is not a reason to say "validate talks to AWS." check blocks warn during plan/apply and do not turn validate into a monitoring tool.

Leave the evaluation-order table (variable validation → preconditions → postconditions → checks) for 4g. Here, do not confuse "a condition failed" with "the VPC exists."

HCP Terraform and CI

HCP Terraform remote runs validate as part of planning on the workspace VM. You still want fmt + validate in pull-request CI so broken HCL never opens a run. A common 1.12 pipeline is:

terraform fmt -check -recursive
terraform init -backend=false
terraform validate -json
# later, on the apply workspace: terraform plan -out=tfplan

That pipeline never asks whether the VPC is still there. The HCP Terraform plan run does.

Scenario: the "valid" module that still cannot apply

Priya publishes an aws_instance module. terraform init -backend=false && terraform validate succeeds in CI: every argument is in schema, var.subnet_id is a string, no missing required fields. A consumer sets subnet_id = "subnet-deadbeef" and runs plan. The AWS provider's read fails; the subnet is gone. Validate was not wrong. It never promised a live lookup. Priya adds a note in the module README: consumers must plan against a real account. She does not replace plan with validate in the apply pipeline.

004 traps for objective 3c

  • validate does not call provider APIs or check that a VPC/AMI/subnet ID exists.
  • fmt is not validation; it is canonical style.
  • plan is the command that refreshes and proposes actions.
  • validate needs init (or init -backend=false) so provider schemas are present.
  • Custom conditions can fail validate; they do not turn validate into a cloud inventory tool.
  • A successful validate is not an apply and does not write state.
Test Your Knowledge

A junior engineer runs terraform validate to confirm that vpc-0abc123 still exists in the AWS account. What should you tell them?

A
B
C
D
Test Your Knowledge

On Terraform 1.12, how do terraform fmt, terraform validate, and terraform plan differ?

A
B
C
D
Test Your Knowledge

Which statement about terraform validate on Terraform 1.12 is correct?

A
B
C
D