diff --git a/helper/schema/schema.go b/helper/schema/schema.go index 931622963..38f3b80d6 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -1440,6 +1440,11 @@ func (m schemaMap) validateList( } } + // schemaMap can't validate nil + if raw == nil { + return nil, nil + } + // We use reflection to verify the slice because you can't // case to []interface{} unless the slice is exactly that type. rawV := reflect.ValueOf(raw) @@ -1518,6 +1523,10 @@ func (m schemaMap) validateMap( } } + // schemaMap can't validate nil + if raw == nil { + return nil, nil + } // We use reflection to verify the slice because you can't // case to []interface{} unless the slice is exactly that type. rawV := reflect.ValueOf(raw) @@ -1644,6 +1653,12 @@ func (m schemaMap) validateObject( schema map[string]*Schema, c *terraform.ResourceConfig) ([]string, []error) { raw, _ := c.Get(k) + + // schemaMap can't validate nil + if raw == nil { + return nil, nil + } + if _, ok := raw.(map[string]interface{}); !ok && !c.IsComputed(k) { return nil, []error{fmt.Errorf( "%s: expected object, got %s", @@ -1688,6 +1703,14 @@ func (m schemaMap) validatePrimitive( raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { + + // a nil value shouldn't happen in the old protocol, and in the new + // protocol the types have already been validated. Either way, we can't + // reflect on nil, so don't panic. + if raw == nil { + return nil, nil + } + // Catch if the user gave a complex type where a primitive was // expected, so we can return a friendly error message that // doesn't contain Go type system terminology. diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 32dc3de44..055e76f26 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -5465,6 +5465,39 @@ func TestSchemaMap_Validate(t *testing.T) { }, Err: false, }, + + "unexpected nils values": { + Schema: map[string]*Schema{ + "strings": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Schema{ + Type: TypeString, + }, + }, + "block": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "int": &Schema{ + Type: TypeInt, + Required: true, + }, + }, + }, + }, + }, + + Config: map[string]interface{}{ + "strings": []interface{}{"1", nil}, + "block": []interface{}{map[string]interface{}{ + "int": nil, + }, + nil, + }, + }, + }, } for tn, tc := range cases {