diff --git a/command/meta_backend.go b/command/meta_backend.go index 47ea97a769..de242932d2 100644 --- a/command/meta_backend.go +++ b/command/meta_backend.go @@ -1038,6 +1038,13 @@ func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.V if err != nil { diags = diags.Append(fmt.Errorf("Error asking for input to configure backend %q: %s", c.Type, err)) } + + // We get an unknown here if the if the user aborted input, but we can't + // turn that into a config value, so set it to null and let the provider + // handle it in PrepareConfig. + if !configVal.IsKnown() { + configVal = cty.NullVal(configVal.Type()) + } } newVal, validateDiags := b.PrepareConfig(configVal) diff --git a/helper/schema/backend.go b/helper/schema/backend.go index 64c3b9f69d..c8d8ae28c6 100644 --- a/helper/schema/backend.go +++ b/helper/schema/backend.go @@ -182,7 +182,11 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics { // that should be populated enough to appease the not-yet-updated functionality // in this package. This should be removed once everything is updated. func (b *Backend) shimConfig(obj cty.Value) *terraform.ResourceConfig { - shimMap := hcl2shim.ConfigValueFromHCL2(obj).(map[string]interface{}) + shimMap, ok := hcl2shim.ConfigValueFromHCL2(obj).(map[string]interface{}) + if !ok { + // If the configVal was nil, we still want a non-nil map here. + shimMap = map[string]interface{}{} + } return &terraform.ResourceConfig{ Config: shimMap, Raw: shimMap, diff --git a/helper/schema/backend_test.go b/helper/schema/backend_test.go index 609ce59678..8b0336fe0e 100644 --- a/helper/schema/backend_test.go +++ b/helper/schema/backend_test.go @@ -31,6 +31,21 @@ func TestBackendPrepare(t *testing.T) { true, }, + { + "Null config", + &Backend{ + Schema: map[string]*Schema{ + "foo": &Schema{ + Required: true, + Type: TypeString, + }, + }, + }, + nil, + map[string]cty.Value{}, + true, + }, + { "Basic required field set", &Backend{ @@ -111,7 +126,11 @@ func TestBackendPrepare(t *testing.T) { for i, tc := range cases { t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) { - configVal, diags := tc.B.PrepareConfig(cty.ObjectVal(tc.Config)) + cfgVal := cty.NullVal(cty.Object(map[string]cty.Type{})) + if tc.Config != nil { + cfgVal = cty.ObjectVal(tc.Config) + } + configVal, diags := tc.B.PrepareConfig(cfgVal) if diags.HasErrors() != tc.Err { for _, d := range diags { t.Error(d.Description())