Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Terraform By James Joyner IV · · 8 min read

Terraform Error: check block assertion failed during plan/apply

Quick answer

Understand Terraform 'Check block assertion failed' warnings: how check{} assert conditions and data-source scoping work, why they don't block apply, and how to fix a failing assertion.

  • #terraform
  • #iac
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Exact Error Message


│ Warning: Check block assertion failed

│   on checks.tf line 8, in check "health":
│    8:     condition = data.http.healthcheck.status_code == 200

│ Service returned status 503, expected 200

When the scoped data source inside the check fails to read, you instead see:

│ Warning: Check block assertion known after apply

│   on checks.tf line 8, in check "health":
│    8:     condition = data.http.healthcheck.status_code == 200

│ The condition could not be evaluated at this time, a result will be
│ known after apply.

What It Means

A check block (Terraform 1.5+) defines custom validation that runs after Terraform builds or refreshes your infrastructure. Unlike precondition/postcondition inside a resource, a failing check assertion produces a warning, not an error — it does not stop terraform apply or mark the run as failed at the CLI exit-code level in the same way a resource error does.

The message above tells you a named assertion (health) evaluated to false, along with your custom error_message. Checks are meant for continuous validation of live properties — endpoint health, certificate expiry, tag policy — so a failing check usually signals a real drift or outage rather than a syntax problem in your HCL.

Common Causes

  • The asserted condition is genuinely false — the endpoint is down, a value drifted, or a policy is violated.
  • A scoped data source inside the check cannot be read yet, so the result is “known after apply.”
  • The condition expression references an attribute that is null or unknown during planning.
  • The check queries an external service (HTTP, DNS) that is flaky or rate-limited.
  • The assertion logic is inverted — you wrote == 200 where the healthy value is something else.

Diagnostic Commands

Run a plan to see which named check is failing and its message:

terraform plan

Run apply with checks evaluated against live infrastructure:

terraform apply

Manually reproduce the underlying probe (HTTP example):

curl -o /dev/null -s -w "%{http_code}\n" https://api.example.com/health

Inspect the value the check reads via console:

echo 'data.http.healthcheck.status_code' | terraform console

Step-by-Step Resolution

  1. Read the warning and identify the named check and the failed condition. Here it is check "health" asserting a 200 status.

  2. Reproduce the probe outside Terraform. If the service truly returns 503, the check is doing its job — fix the infrastructure, not the check:

curl -i https://api.example.com/health
  1. If you want the check to allow multiple healthy codes, widen the condition rather than deleting the check:
check "health" {
  data "http" "healthcheck" {
    url = "https://api.example.com/health"
  }

  assert {
    condition     = contains([200, 204], data.http.healthcheck.status_code)
    error_message = "Health endpoint returned ${data.http.healthcheck.status_code}, expected 200 or 204."
  }
}
  1. If the message is “known after apply,” the scoped data source could not be read during plan. That is expected for values that depend on resources being created — run terraform apply and let the check evaluate post-apply.

  2. Guard against null/unknown attributes so the assertion evaluates cleanly:

assert {
  condition     = data.http.healthcheck.status_code != null && data.http.healthcheck.status_code == 200
  error_message = "Health endpoint unavailable or unhealthy."
}
  1. Re-run and confirm the warning clears:
terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Prevention

  • Use check blocks for continuous, non-blocking validation (health, expiry, policy) and reserve resource precondition/postcondition for hard invariants that must block apply.
  • Scope data sources inside the check block so a probe failure degrades to a check warning instead of failing the whole plan.
  • Write assertions that tolerate the full set of healthy values with contains(...) rather than a single equality.
  • Always set a descriptive error_message that interpolates the observed value, so the warning is actionable at a glance.
  • Wire check warnings into CI notifications, since they do not fail the run by default. The Terraform validation prompts can help you draft robust assert conditions and error messages.
  • Resource postcondition failed — a blocking condition inside a resource lifecycle block, which does fail apply.
  • Invalid function argument — a malformed expression inside the check’s condition.
  • Data source read failed — the scoped data source errored rather than returning an assertable value.
  • Output refers to sensitive values — unrelated, but often surfaces alongside checks that read secret-bearing data.

Frequently Asked Questions

Does a failing check block stop terraform apply? No. Check assertions raise warnings, not errors, so apply completes. This is intentional — checks are for ongoing monitoring, not gating.

How is a check block different from a precondition? A precondition/postcondition lives inside a resource and blocks the operation when it fails; a check block is standalone, runs after apply, and only warns. Use checks for health and drift monitoring.

Why does my check say ‘known after apply’? The scoped data source depends on resources that don’t exist yet at plan time, so Terraform defers evaluation until after apply. This is normal for checks that probe freshly created infrastructure.

Can I make a failing check fail my CI pipeline? Not directly through the exit code. Parse terraform apply output or use -json to detect check warnings and fail the build yourself. For more validation patterns, see the Terraform guides.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.