hashicorp / hashicorp/terraform-plugin-framework

Provider produced invalid plan error when planning certain high-precision floating point numbers

Open
#1,017 0 comments 0 reactions 0 assignees View on GitHub
bug types
Dominant language
Go
Stars
384
Forks
107
Avg merge
3m
Merged PRs (30d)
1

Description

## Problem Statement
When round-tripping certain floating point numbers such as `MaxFloat32` from Terraform config to a `type.Float32` or a `type.Float64` framework type:

```terraform
resource "framework_float64_precision" "test" {
float64_attribute = 340282346638528859811704183484516925440
}
```
Applying the above config results in the following error from Terraform:
```

│ Error: Provider produced invalid plan

│ Provider "registry.terraform.io/hashicorp/scaffolding" planned an invalid value for scaffolding_float32_precision.test.float32_attribute: planned value
│ cty.NumberIntVal(3.4028234663852886e+38) does not match config value cty.NumberIntVal(3.4028234663852885981170418348451692544e+38).

│ This is a bug in the provider, which should be reported in the provider's own issue tracker.

```

## Context:
Floating point numbers in Terraform configuration are parsed in Terraform core as [strings with 512 bit precision](https://github.com/hashicorp/go-cty/blob/85980079f637862fa8e43ddc82dd74315e2f4c85/cty/value_init.go#L49) into a `big.Float` object. Most floating point numbers that are roundtripped in the framework into either a `type.Float32Value` or a `type.Float64Value` via a float32 or float64 conversion will introduce some accuracy loss in the floating point value.

Floating point numbers are compared using `(big.Float).Cmp()` in the [framework](https://github.com/hashicorp/terraform-plugin-framework/blob/main/types/basetypes/float64_value.go#L141) and in [terraform-plugin-go](https://github.com/hashicorp/terraform-plugin-go/blob/129bc5ed3abb6fe961c5e5c3877a96d46f0d132b/tftypes/value_equal.go#L132) but when Terraform core compares numbers to ensure value consistency, it uses it's [JSON string representation](https://github.com/zclconf/go-cty/blob/7b73cce468e8021d933cfb7990356837c6348146/cty/primitive_type.go#L94). Essentially, two numbers are considered the same in Terraform core only when they write the same JSON.

There are a certain subset of numbers where a conversion from the 512-bit precision `big.Float` object to either a float64 or float32 value does not result in any accuracy loss (they have the exact same binary representation). These numbers will be considered equal when compared using `(big.Float).Cmp()` but will write different JSON strings such that Terraform core will consider them different numbers.

The number has to meet the following conditions to run into this error (first two points from https://stackoverflow.com/a/67145511):
- The number must be rational (can be expressed as a fraction of integers)
- The denominator of such fraction must be a power of two (1, 2, 4, 8, etc.)
- The number in Terraform config must must write to JSON with more precision than it's float64/float32 equivalent

This issue affects both `types.Float32` and `types.Float64`

## Potential Solutions:
To fix this issue, we would likely need to change the number comparison logic in both the framework and terraform-plugin-go to ensure that the 512-bit precision `big.Float` object is sent to Terraform core during the `ReadResource`, `ReadDatasource` and `ApplyResourceChange` RPCs as well as modifying the logic during `PlanResourceChange` RPC to send the correct value during planning

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.