Terraform: Syntax error when attempting to divide a float string

Created on 31 May 2017  ·  12Comments  ·  Source: hashicorp/terraform

Terraform Version

Terraform v0.9.6

Affected Resource(s)

  • core

This is a bug with Terraform's interpolation - it attempts to parse all strings as integers rather than floats when performing math operations.

Terraform Configuration Files

Minimal example:

module/main.tf:

variable "dividend" {}
variable "divisor" {}

resource "local_file" "dividing" {
  content = "${var.dividend / var.divisor}"
  filename = "${path.module}/test.txt"
}

division.tf:

module "dividing" {
  source = "./module"
  dividend = 1.5
  divisor = 2
}

Output

1 error(s) occurred:

* module.dividing.local_file.dividing: 1 error(s) occurred:

* module.dividing.local_file.dividing: __builtin_StringToInt: strconv.ParseInt: parsing "1.5": invalid syntax in:

${var.dividend / var.divisor}

Debug Output

https://gist.github.com/ThePletch/1ba6cbd8075fff774403dd39557b2a66

Expected Behavior

content is set to 0.75

Actual Behavior

Terraform reports a syntax error.

Steps to Reproduce

  1. Set up the above Terraform config files
  2. terraform plan
bug config

Most helpful comment

Hi @ThePletch! Sorry for this broken behavior.

As you said, this is indeed an issue in Terraform's interpolation language. Specifically, it is that it currently distinguishes integers from floats but when asked to convert a string to a number it currently prefers the int conversion, rather than inspecting the string to decide which path to take.

We're currently in the early stages of designing some changes to the configuration language, and one of the ideas on the table is to remove this integer vs. float distinction altogether and just use arbitrary-precision decimal numbers, and indeed issues like this are the primary motivators for that path.

In the mean time, this can be worked around by forcing the desired conversion using the builtin function that, behind the scenes, deals with converting these values:

```hcl
content = "${__builtin_StringToFloat(var.dividend) / __builtin_StringToFloat(var.divisor)}"
````

This is unfortunately rather depending on an implementation detail and so may need to be adjusted in future when we make the aforementioned configuration language changes, so I would suggest using this technique only sparingly, but hopefully this helps you solve your problem in the short term until we can address this properly.

All 12 comments

Hi @ThePletch! Sorry for this broken behavior.

As you said, this is indeed an issue in Terraform's interpolation language. Specifically, it is that it currently distinguishes integers from floats but when asked to convert a string to a number it currently prefers the int conversion, rather than inspecting the string to decide which path to take.

We're currently in the early stages of designing some changes to the configuration language, and one of the ideas on the table is to remove this integer vs. float distinction altogether and just use arbitrary-precision decimal numbers, and indeed issues like this are the primary motivators for that path.

In the mean time, this can be worked around by forcing the desired conversion using the builtin function that, behind the scenes, deals with converting these values:

```hcl
content = "${__builtin_StringToFloat(var.dividend) / __builtin_StringToFloat(var.divisor)}"
````

This is unfortunately rather depending on an implementation detail and so may need to be adjusted in future when we make the aforementioned configuration language changes, so I would suggest using this technique only sparingly, but hopefully this helps you solve your problem in the short term until we can address this properly.

@apparentlymart Your solution appears to have temporarily solved the problem for me- it's been nearly a year now, has there been any further development on this issue?

We are now in the late stages of implementing the change I mentioned in my previous comment, where we did conclude that removing the integer vs. float distinction was the right path.

It is planned for this, along with a number of other configuration language improvements, to be included in the next major release. This work is the current focus for the Terraform team at HashiCorp.

In line with my concern when sharing the previous workaround, since those __builtin_ functions are not "real functions" (they are an implementation detail of the automatic type conversions), it will probably be necessary to remove those when upgrading to the new version, reverting to the more intuitive form:

  # (not yet implemented)
  content = var.dividend / var.divisor

In many cases we're able to automatically handle certain changes during upgrade, so hopefully this will be one of those situations. We'll have more specific details on this once we get closer to finished implementation, where we'll start working through open issues to validate they are fixed and post further updates.

Much thanks for the update. I would agree from an outside perspective with that choice. I'll make sure to mark the "hacky" code to be fixed with the next major release.

Hi @apparentlymart I had the same problem and tested your "hacky"solution. It works.Thanks!

Any update on the more general solution? Any PR under review?

Why yes! We do have an update!
https://www.hashicorp.com/blog/terraform-0-1-2-preview 🎉

Hi all!

Terraform v0.12.0-alpha1 now includes the promised fix for this issue, where Terraform no longer makes a distinction between integer and float numbers and instead just has a single arbitrary-precision number type.

By using the terraform console from the v0.12.0-alpha1 build I can verify that things are now working as expected:

> "1.5" / "2"
0.75
> 1.5 / 2
0.75
> floor(1.5) / 2
0.5

As I'd warned previously, the automatic conversions are no longer represented internally as undocumented functions, and so the __builtin_StringToFloat workaround will need to be undone as part of preparing a module for v0.12.0 compatibility.

Since this is fixed in master, I'm going to close this out. The fix will be included in the v0.12.0 final release. Thanks for reporting this, and thanks also for your patience while we laid the groundwork to fix it.

An alternative for Terraform 0.11 is to declare the floating point value as an interpolated equation:

dividend = "${15 / 10}"

This is a little easier on the eyes, and it is likely future-proof in a way that __builtin_StringToFloat is not (though @apparentlymart may have something to say about that).

@jugglinmike that does indeed look like a better forward-looking workaround, if it gets you what you need. Thanks for sharing it!

I think it may still run into the same bug in certain cases when used with references to string variables, though. That incorrect automatic conversion rule (using int rather than float) would still apply if either operand were a string.

Got it. Looking forward to 0.12--thanks for the excellent tool and your continued support :)

The workaround I suggested above is incorrect. It avoids the bug because it forces the implicit Integer casting in Terraform 0.11 and below, not because it works around the parsing issue.

I'd still like to avoid relying on __builtin_StringToFloat because it's undocumented and expected to be removed in the next minor release. From my limited understanding, the parser is more tolerant of floating point values when they appear within parameter lists. That means that the semantics of __builtin_StringToFloat aren't strictly necessary. Any function should do, as long as it doesn't modify the value, of course. max fits the bill:

$ echo '"${"-1.1" + 2}"' | terraform console
__builtin_StringToInt: strconv.ParseInt: parsing "-1.1": invalid syntax in:

${"${"-1.1" + 2}"}
$ echo '"${max("-1.1") + 2}"' | terraform console
0.8999999999999999

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.

Was this page helpful?
0 / 5 - 0 ratings