diff --git a/helper/schema/schema.go b/helper/schema/schema.go index f4d860995700..8ed8135264a3 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -1178,8 +1178,25 @@ func (m schemaMap) validatePrimitive( raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { + + // 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. + switch reflect.ValueOf(raw).Type().Kind() { + case reflect.Slice: + return nil, []error{ + fmt.Errorf("%s must be a single value, not a list", k), + } + case reflect.Map: + return nil, []error{ + fmt.Errorf("%s must be a single value, not a map", k), + } + default: // ok + } + if c.IsComputed(k) { - // If the key is being computed, then it is not an error + // If the key is being computed, then it is not an error as + // long as it's not a slice or map. return nil, nil } diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 09eeef119e6e..e43300c9988d 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -3409,6 +3409,36 @@ func TestSchemaMap_Validate(t *testing.T) { Err: true, }, + "Bad, should not allow lists to be assigned to string attributes": { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Required: true, + }, + }, + + Config: map[string]interface{}{ + "availability_zone": []interface{}{"foo", "bar", "baz"}, + }, + + Err: true, + }, + + "Bad, should not allow maps to be assigned to string attributes": { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Required: true, + }, + }, + + Config: map[string]interface{}{ + "availability_zone": map[string]interface{}{"foo": "bar", "baz": "thing"}, + }, + + Err: true, + }, + "Deprecated attribute usage generates warning, but not error": { Schema: map[string]*Schema{ "old_news": &Schema{