From fd56aded083c3441428dbb84fff43b118ce9a2f5 Mon Sep 17 00:00:00 2001 From: cverheyde Date: Fri, 17 Apr 2026 00:11:13 +0200 Subject: [PATCH 1/2] budgets: normalize limit_amount to avoid scientific notation breaking UpdateBudget --- internal/service/budgets/budget.go | 6 +- internal/service/budgets/budget_test.go | 80 +++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/internal/service/budgets/budget.go b/internal/service/budgets/budget.go index fb0bdaad7ec2..562dbd4d09d2 100644 --- a/internal/service/budgets/budget.go +++ b/internal/service/budgets/budget.go @@ -540,7 +540,11 @@ func resourceBudgetRead(ctx context.Context, d *schema.ResourceData, meta any) d } if budget.BudgetLimit != nil { - d.Set("limit_amount", budget.BudgetLimit.Amount) + amount := aws.ToString(budget.BudgetLimit.Amount) + if d, err := decimal.NewFromString(amount); err == nil { + amount = d.String() + } + d.Set("limit_amount", amount) d.Set("limit_unit", budget.BudgetLimit.Unit) } diff --git a/internal/service/budgets/budget_test.go b/internal/service/budgets/budget_test.go index 60ed674a3eea..5ffc9d7b853a 100644 --- a/internal/service/budgets/budget_test.go +++ b/internal/service/budgets/budget_test.go @@ -457,6 +457,54 @@ func TestAccBudgetsBudget_notifications(t *testing.T) { }) } +func TestAccBudgetsBudget_largeLimitAmountUpdate(t *testing.T) { + ctx := acctest.Context(t) + var budget awstypes.Budget + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + resourceName := "aws_budgets_budget.test" + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BudgetsEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BudgetsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckBudgetDestroy(ctx, t), + Steps: []resource.TestStep{ + { + Config: testAccBudgetConfig_largeLimitAmount(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckBudgetExists(ctx, t, resourceName, &budget), + resource.TestCheckResourceAttr(resourceName, "budget_type", "COST"), + // Do not assert exact limit_amount string representation here. + // Large values may currently round-trip in scientific notation. + // The purpose of this test is to verify that the in-place update succeeds, not to fail here. + // resource.TestCheckResourceAttr(resourceName, "limit_amount", "25100000"), + resource.TestCheckResourceAttr(resourceName, "limit_unit", "USD"), + resource.TestCheckResourceAttr(resourceName, "time_unit", "ANNUALLY"), + resource.TestCheckResourceAttr(resourceName, "notification.#", "0"), + ), + }, + { + Config: testAccBudgetConfig_largeLimitAmountUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckBudgetExists(ctx, t, resourceName, &budget), + resource.TestCheckResourceAttr(resourceName, "budget_type", "COST"), + resource.TestCheckResourceAttr(resourceName, "limit_unit", "USD"), + resource.TestCheckResourceAttr(resourceName, "time_unit", "ANNUALLY"), + resource.TestCheckResourceAttr(resourceName, "notification.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "notification.*", map[string]string{ + "comparison_operator": "GREATER_THAN", + "notification_type": "ACTUAL", + "subscriber_email_addresses.#": "1", + "subscriber_sns_topic_arns.#": "0", + "threshold": "80", + "threshold_type": "PERCENTAGE", + }), + ), + }, + }, + }) +} + func TestAccBudgetsBudget_plannedLimits(t *testing.T) { ctx := acctest.Context(t) var budget awstypes.Budget @@ -916,6 +964,38 @@ resource "aws_budgets_budget" "test" { `, rName, emailAddress1) } +func testAccBudgetConfig_largeLimitAmount(rName string) string { + return fmt.Sprintf(` +resource "aws_budgets_budget" "test" { + name = %q + budget_type = "COST" + limit_amount = "25100000" + limit_unit = "USD" + time_unit = "ANNUALLY" +} +`, rName) +} + +func testAccBudgetConfig_largeLimitAmountUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_budgets_budget" "test" { + name = %q + budget_type = "COST" + limit_amount = "25100000" + limit_unit = "USD" + time_unit = "ANNUALLY" + + notification { + comparison_operator = "GREATER_THAN" + threshold = 80 + threshold_type = "PERCENTAGE" + notification_type = "ACTUAL" + subscriber_email_addresses = ["terraform-aws-provider-test@example.com"] + } +} +`, rName) +} + func testAccBudgetConfig_plannedLimits(rName, config string) string { return fmt.Sprintf(` resource "aws_budgets_budget" "test" { From 1122f7c100410bc40c734fff5cb188028df9a809 Mon Sep 17 00:00:00 2001 From: cverheyde Date: Fri, 17 Apr 2026 00:56:00 +0200 Subject: [PATCH 2/2] changelog: add budgets limit_amount fix entry --- .changelog/47487.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/47487.txt diff --git a/.changelog/47487.txt b/.changelog/47487.txt new file mode 100644 index 000000000000..687070eedc83 --- /dev/null +++ b/.changelog/47487.txt @@ -0,0 +1,2 @@ +```release-note:bug +budgets: fix UpdateBudget failure when `limit_amount` is returned in scientific notation