Terraform Error: check block assertion failed during plan/apply
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
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
datasource inside the check cannot be read yet, so the result is “known after apply.” - The
conditionexpression references an attribute that isnullor unknown during planning. - The check queries an external service (HTTP, DNS) that is flaky or rate-limited.
- The assertion logic is inverted — you wrote
== 200where 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
-
Read the warning and identify the named check and the failed
condition. Here it ischeck "health"asserting a 200 status. -
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
- 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."
}
}
-
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 applyand let the check evaluate post-apply. -
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."
}
- Re-run and confirm the warning clears:
terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Prevention
- Use
checkblocks for continuous, non-blocking validation (health, expiry, policy) and reserve resourceprecondition/postconditionfor 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_messagethat 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.
Related Errors
Resource postcondition failed— a blocking condition inside a resourcelifecycleblock, which does fail apply.Invalid function argument— a malformed expression inside the check’scondition.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.
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.