Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.13 function merge() returns null #26268

Closed
zamerman opened this issue Sep 16, 2020 · 4 comments
Closed

0.13 function merge() returns null #26268

zamerman opened this issue Sep 16, 2020 · 4 comments
Assignees
Labels
bug confirmed a Terraform Core team member has reproduced this issue v0.13 Issues (primarily bugs) reported against v0.13 releases v0.14 Issues (primarily bugs) reported against v0.14 releases

Comments

@zamerman
Copy link

zamerman commented Sep 16, 2020

Terraform Version

0.13.2

Terraform Configuration Files

locals {
  project_role_bindings1 = merge([{a=2}, {c=1}]...)
  project_role_bindings2 = merge([]...)
  project_role_bindings3 = merge()
}


output out1 {
  value = local.project_role_bindings1
}

output out2 {
  value = local.project_role_bindings2
}

output out3 {
  value = local.project_role_bindings3
}

Debug Output

Crash Output

Expected Behavior

According to the documentation, "merge takes an arbitrary number of maps or objects, and returns a single map or object that contains a merged set of elements from all arguments." So the result should be something like:

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

out1 = {
  "a" = 2
  "c" = 1
}
out2 = {}
out3 = {}

Actual Behavior

In reality when the merge function has no parameters it returns null. out2 and out3 outputs are suppressed. Therefore in cases in which the return of the merge function is used by some other function or code expecting a list the code fails.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

out1 = {
  "a" = 2
  "c" = 1
}

Steps to Reproduce

  1. terraform init
  2. terraform apply

Additional Context

Our code is using the return of the merge function in the transpose function. The transpose function expects a map and its argument cannot be null. So we receive the following error:

Error: Invalid function argument 

...

Invalid value for "values" parameter: argument must not be null.

Our code worked in Terraform 0.12, it is only after changing to Terraform 0.13 that the error occurred. So this is a behavior change from 0.12 to 0.13.

References

@zamerman zamerman added bug new new issue not yet triaged labels Sep 16, 2020
@zamerman zamerman changed the title function merge() returns 0.13 function merge() returns null Sep 16, 2020
@apparentlymart
Copy link
Contributor

Hi @zamerman! Thanks for this bug report.

I reproduced this easily using terraform console on a development build of Terraform 0.14:

> merge({})
{}
> merge()
null

In the implementation of this function, it seems like it's intentionally accepting and ignoring null values, rather than returning an error saying that the argument must be an object:

> merge(null)
null
> merge(null, {})
{}

...and so this behavior of merge() returning null seems to be coming as an edge case of the rule "if all of the arguments are null then return null", because having no arguments at all is treated by this logic as them "all being null".

I think in order to decide what to do here we'll need to first do some code archaeology to determine what prompted having the merge function silently ignore null rather than returning an error (as is typical for most other Terraform language features). At first glance I agree that it seems intuitive for merge() to return {} (e.g. so that merge(var.empty_list_of_objects...) can return {}), but the fact that there is some special handling of null here suggests that this behavior was added to allow for some special use-case that might be now broken by changing the behavior in retrospect.

@apparentlymart apparentlymart added confirmed a Terraform Core team member has reproduced this issue v0.13 Issues (primarily bugs) reported against v0.13 releases v0.14 Issues (primarily bugs) reported against v0.14 releases and removed new new issue not yet triaged labels Sep 16, 2020
@mildwonkey mildwonkey self-assigned this Dec 11, 2020
@mildwonkey
Copy link
Contributor

I did some digging, and this function has been largely unchanged since it was brought over to go-cty from terraform v0.11. There are no comments and no documentation that describe why this choice was made, so I think we're ok to (cautiously) change it for v0.15:

Since terraform v0.11 didn't have a concept of null values, and merge would return an error if there were no arguments, I'm inclined to update the behavior so it will return an error if there are no arguments or if all arguments are null, while still accepting null arguments as long as there is at least one valid argument.

This is the closest one could get to merging "null" in v0.11:

> merge()
1:3: merge: expected 1 arguments, got 0 in:

${merge()}

Empty maps are fine (non-null) in v0.11:

> merge(map())
{}

@mildwonkey
Copy link
Contributor

👋 Sorry for the delay! I made this change in go-cty and failed to link that upstream PR : zclconf/go-cty#82

The cty dependency has been updated in terraform, so I will close this. Thanks!

$ terraform console
> merge()
{}

@ghost
Copy link

ghost commented Apr 11, 2021

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked as resolved and limited conversation to collaborators Apr 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug confirmed a Terraform Core team member has reproduced this issue v0.13 Issues (primarily bugs) reported against v0.13 releases v0.14 Issues (primarily bugs) reported against v0.14 releases
Projects
None yet
Development

No branches or pull requests

3 participants