Terraform v0.12.20
main.tf:
module mod1 {
source = "./mod1"
optional_input = null
}
mod1/main.tf:
variable optional_input {
default = 5
}
output foo {
value = var.optional_input / 5
}
https://pastebin.com/raw/NuxLJi2U
As per docs:
null: a value that represents absence or omission. If you set an argument of a resource or module to null, Terraform behaves as though you had completely omitted it — it will use the argument's default value if it has one
An error message is shown saying that the said argument must not be null:
on mod1/main.tf line 6, in output "foo":
6: value = var.optional_input / 5
|----------------
| var.optional_input is null
Error during operation: argument must not be null.
terraform initterraform applyThis forces module consumers to have knowledge of the default value for the module and specify the same default in their variable definitions. This really should be fixed.
Can reproduce in 0.12.25, see comment in #21702
Hi @oxplot,
I agree that the behavior is inconsistent here, and that's confusing. My sense of the ideal behavior is that if a variable value is set to null then the default value should be taken, and that setting a required variable (one without a default) should be an error.
The design challenge in this area is that some modules use null as a valid value, and so changes to the behavior must consider that. In the provider schema system that is represented by explicitly marking a variable as "optional" without providing a default. That approach doesn't directly work for input variables because the presence of default is overloaded to _imply_ "optional", rather than it being a separate argument.
We could potentially address this by allowing default = null as a special way to declare a variable as optional without a default value. That is still inconsistent with the usual meaning of null as being equivalent to omitting the argument -- omitting default would have a different meaning than setting it to null -- but a special case unique to the variable default argument is better than one that applies to all input variables, and default doesn't accept conditional expressions anyway so there isn't really any other useful meaning of default = null.
Unfortunately, given that the current behavior was established in v0.12.0 we cannot just change it now because there will be many modules depending on the current behavior. I'm going to mark this as a breaking change to acknowledge that while it's a valid issue to be addressed we are blocked by finding a responsible way to introduce it that will not cause confusing misbehavior for existing modules. I don't yet know what that approach will be.
In the meantime, I think it'd be best to update the documentation for module blocks to be explicit about this exception to the usual interpretation of null, so that the behavior is at least well-defined even if also inconsistent.
Thanks for reporting this!
@apparentlymart I think it's important to consider the converse...a default that is non null that a consumer of the module may or may not set, yet the configuration has to allow for it. This gets even more complex in chained module configurations.
Agreed that this is unexpected behavior, especially considering the documentation for null in the Expressions documentation.
null: a value that represents absence or omission. If you set an argument of a resource or module to null, Terraform behaves as though you had completely omitted it — it will use the argument's default value if it has one, or raise an error if the argument is mandatory.
Most helpful comment
Hi @oxplot,
I agree that the behavior is inconsistent here, and that's confusing. My sense of the ideal behavior is that if a variable value is set to
nullthen the default value should be taken, and that setting a required variable (one without a default) should be an error.The design challenge in this area is that some modules use
nullas a valid value, and so changes to the behavior must consider that. In the provider schema system that is represented by explicitly marking a variable as "optional" without providing a default. That approach doesn't directly work for input variables because the presence ofdefaultis overloaded to _imply_ "optional", rather than it being a separate argument.We could potentially address this by allowing
default = nullas a special way to declare a variable as optional without a default value. That is still inconsistent with the usual meaning ofnullas being equivalent to omitting the argument -- omittingdefaultwould have a different meaning than setting it tonull-- but a special case unique to the variabledefaultargument is better than one that applies to all input variables, anddefaultdoesn't accept conditional expressions anyway so there isn't really any other useful meaning ofdefault = null.Unfortunately, given that the current behavior was established in v0.12.0 we cannot just change it now because there will be many modules depending on the current behavior. I'm going to mark this as a breaking change to acknowledge that while it's a valid issue to be addressed we are blocked by finding a responsible way to introduce it that will not cause confusing misbehavior for existing modules. I don't yet know what that approach will be.
In the meantime, I think it'd be best to update the documentation for module blocks to be explicit about this exception to the usual interpretation of
null, so that the behavior is at least well-defined even if also inconsistent.Thanks for reporting this!