diff --git a/.changes/v1.15/BUG FIXES-20260305-120000.yaml b/.changes/v1.15/BUG FIXES-20260305-120000.yaml new file mode 100644 index 000000000000..6b7e67dc2f97 --- /dev/null +++ b/.changes/v1.15/BUG FIXES-20260305-120000.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: 'configs: fix nil pointer panic when a moved block has invalid addresses (e.g. quoted strings)' +time: 2026-03-05T12:00:00.000000+00:00 +custom: + Issue: "34041" diff --git a/internal/configs/module_test.go b/internal/configs/module_test.go index 89d42556fc2c..05f92344d0bb 100644 --- a/internal/configs/module_test.go +++ b/internal/configs/module_test.go @@ -131,6 +131,16 @@ func TestModule_required_providers_multiple(t *testing.T) { } } +// Moved blocks with invalid (e.g. quoted) addresses combined with import +// blocks should produce errors but must not panic. +// https://github.com/hashicorp/terraform/issues/34041 +func TestModule_moved_with_invalid_addresses_no_panic(t *testing.T) { + _, diags := testModuleFromDir("testdata/invalid-modules/moved-with-invalid-addresses") + if !diags.HasErrors() { + t.Fatal("module should have error diags, but does not") + } +} + // A module may have required_providers configured in files loaded later than // resources. These provider settings should still be reflected in the // resources' configuration. diff --git a/internal/configs/moved.go b/internal/configs/moved.go index 11bc9fdfde09..a51c06b1acab 100644 --- a/internal/configs/moved.go +++ b/internal/configs/moved.go @@ -44,18 +44,20 @@ func decodeMovedBlock(block *hcl.Block) (*Moved, hcl.Diagnostics) { } } + if diags.HasErrors() { + return nil, diags + } + // we can only move from a module to a module, resource to resource, etc. - if !diags.HasErrors() { - if !moved.From.MightUnifyWith(moved.To) { - // We can catch some obviously-wrong combinations early here, - // but we still have other dynamic validation to do at runtime. - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid \"moved\" addresses", - Detail: "The \"from\" and \"to\" addresses must either both refer to resources or both refer to modules.", - Subject: &moved.DeclRange, - }) - } + if !moved.From.MightUnifyWith(moved.To) { + // We can catch some obviously-wrong combinations early here, + // but we still have other dynamic validation to do at runtime. + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid \"moved\" addresses", + Detail: "The \"from\" and \"to\" addresses must either both refer to resources or both refer to modules.", + Subject: &moved.DeclRange, + }) } return moved, diags diff --git a/internal/configs/moved_test.go b/internal/configs/moved_test.go index 4b1948e7e282..f4d8ad4e5295 100644 --- a/internal/configs/moved_test.go +++ b/internal/configs/moved_test.go @@ -118,10 +118,7 @@ func TestMovedBlock_decode(t *testing.T) { }), DefRange: blockRange, }, - &Moved{ - From: mustMoveEndpointFromExpr(foo_expr), - DeclRange: blockRange, - }, + nil, "Missing required argument", }, "error: type mismatch": { diff --git a/internal/configs/testdata/invalid-modules/moved-with-invalid-addresses/moved-invalid.tf b/internal/configs/testdata/invalid-modules/moved-with-invalid-addresses/moved-invalid.tf new file mode 100644 index 000000000000..783d609f1cdf --- /dev/null +++ b/internal/configs/testdata/invalid-modules/moved-with-invalid-addresses/moved-invalid.tf @@ -0,0 +1,16 @@ +# Quoted addresses (issue #34041) +moved { + from = "module.foo" + to = "module.bar" +} + +# Unqualified resource names without type prefix (issue #34162) +moved { + from = bar + to = foo +} + +import { + to = test_instance.foo + id = "test" +}