terraform enabled = false Cannot Tear Down an Env
※本記事にはアフィリエイトリンクを含む場合があります。内容は広告の有無に影響されません。
結論
An enabled flag on a terraform module only switches off count inside it; the module call is always evaluated, so anything reading its output gets null and the flag cannot tear down an environment.
The short version
To fold an environment, use destroy. Bulk-rewriting to enabled = false will not tear it down.
Giving modules a flag like enabled is a common arrangement. If the flag can stop resources being created, folding an entire environment looks like a matter of setting them all to false. It is not.
What enabled switches off is count inside the module and nothing else. The module call itself is always evaluated. The resources go away while the outputs stay defined, their values becoming null. That null flows straight through to whatever reads them.
What it looks like
Set every module in an environment to enabled = false and run plan, and this comes out.
Error: Invalid template interpolation value
The way it appears is distinctive.
- The error surfaces in the module doing the reading, not in the one you disabled
- It appears once for every reference, all at once. Not one at a time as you fix them — all of them from the start
- The failure is at configuration evaluation, and not a single resource has been removed
In practice, dropping one module holding a registry knocked over 13 modules simultaneously — every one interpolating that URL into a string. We had switched off one.
Why
An enabled flag is usually implemented like this.
resource "google_artifact_registry_repository" "this" {
count = var.enabled ? 1 : 0
# ...
}
With count = 0 the resource is not created. So far, as intended.
The problem is outside it. The call module "artifact_registry" { ... } is evaluated whatever enabled is. The module’s output stays defined too. Since the resource inside does not exist, only the value becomes null.
enabled = true → image_repo_url = <the registry URL>
enabled = false → image_repo_url = null ← the definition remains, only the value goes
The reading side embeds that output in a string.
image = "${module.artifact_registry.image_repo_url}/<image>:${var.image_tag}"
The moment it tries to embed null in a string, that is Invalid template interpolation value. terraform is only saying “this value cannot be a string”; it never mentions enabled at all. There is no path from the error message back to the module that caused it.
Why “set them all to false” looks like it will work
Seen one module at a time, this operation works correctly. A module at a leaf of the dependency graph can be set to false and nothing happens, because nobody reads it. And verification tends to stop there.
It only breaks when you drop a module near the root. And folding an entire environment necessarily includes the root. The success of the individual trial is exactly what betrays you.
Fixing it
Use destroy.
terraform -chdir=infrastructure/terraform/envs/<env> destroy
destroy deletes the resources in state and does not break references. The code stays valid; only the real things disappear. There is no need to touch enabled.
If the code stays around after folding, rather than rewriting enabled to false, put it in a state where that root is never applied again. Rewrite it and the next person to run plan hits the same error.
Making it not recur
We wrote it in the runbook. That alone does not reach anyone, though. Teardown is not something you do several times a year, so there is no guarantee the runbook gets opened at the moment.
So we added a second location. The file anyone attempting a teardown will certainly open — the top of the target root’s main.tf — carries the same thing in three lines.
- Tear down with
destroy(the command, verbatim) - A bulk rewrite to
enabled = falsecannot tear down (with the fact that it was tried and failed) - The way back in if it is restored (applying in dependency order, and that values not in the code have to be re-entered)
A runbook only reaches people who go looking. A root main.tf is opened by anyone about to tear something down, without exception. Putting it where it lands beats writing a better runbook.
We kept the enabled flag itself. It is usable for putting an individual module to sleep. What it cannot do is tear down a whole environment, and that is not a problem with the flag. Keeping sleep and teardown as separate operations avoids the trap.
Another case of an error message that does not point at its cause is in Why a SECURITY DEFINER function fails only in production: the owner role. That one produced no error at all.
よくある質問
Q1What is the difference between enabled = false and terraform destroy?
enabled = false sets count to 0 inside the module and stops resources being created, while the module call keeps being evaluated. Outputs stay defined but become null, and that null flows onward. destroy actually deletes the resources in state, without breaking references.
Q2Why does Invalid template interpolation value appear?
It appears when null lands inside string interpolation. Here, whatever reads a disabled module's output receives null, and it fails the moment that gets embedded in a string. The error surfaces in the file doing the interpolation, not in the module that caused it, and once for every reference.
Q3Is the enabled flag itself a design mistake?
It is just for a different purpose. It works for putting an individual module to sleep temporarily. What it cannot do is tear down a whole environment: drop a module near the root of the dependency graph and everything reading its output falls over in a chain.
Q4Can it be restored after teardown?
Partly from code and partly not. Resources under terraform's management can be rebuilt by applying in dependency order, but anything not in the code — the actual values of secrets, say — has to be re-entered. Treat teardown as irreversible and write down in advance what has to be re-entered by hand.
この記事の根拠
- ドキュメントファイル 1〜12行目
- Terraformファイル 1〜21行目
本文の主張は、上の記録に書かれていることだけです。運用しているリポジトリは非公開のため リンクは張れませんが、どのファイルの何行目を、どのコミット時点で見て書いたかは 記事ごとに残しています。推測で書いた箇所はありません。