{"record":{"id":"e2b10d09a3593ff5","repo":"hashicorp/terraform","slug":"s-type-and-nestedtype-cannot-both-be-set","errorCode":null,"errorMessage":"%s: Type and NestedType cannot both be set","messagePattern":"(.+?): Type and NestedType cannot both be set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configs/configschema/internal_validate.go","lineNumber":165,"sourceCode":"\t\terr = errors.Join(err, fmt.Errorf(\"%s%s: must set Optional, Required or Computed\", prefix, name))\n\t}\n\tif a.Optional && a.Required {\n\t\terr = errors.Join(err, fmt.Errorf(\"%s%s: cannot set both Optional and Required\", prefix, name))\n\t}\n\tif a.Computed && a.Required {\n\t\terr = errors.Join(err, fmt.Errorf(\"%s%s: cannot set both Computed and Required\", prefix, name))\n\t}\n\tif !a.Deprecated && a.DeprecationMessage != \"\" {\n\t\terr = errors.Join(err, fmt.Errorf(\"%s%s: DeprecationMessage must not be set when Deprecated is false\", prefix, name))\n\t}\n\n\tif a.Type == cty.NilType && a.NestedType == nil {\n\t\terr = errors.Join(err, fmt.Errorf(\"%s%s: either Type or NestedType must be defined\", prefix, name))\n\t}\n\n\tif a.Type != cty.NilType {\n\t\tif a.NestedType != nil {\n\t\t\terr = errors.Join(fmt.Errorf(\"%s: Type and NestedType cannot both be set\", name))\n\t\t}\n\t}\n\n\tif a.NestedType != nil {\n\t\tswitch a.NestedType.Nesting {\n\t\tcase NestingSingle, NestingMap, NestingGroup:\n\t\t\t// no validations to perform\n\t\tcase NestingList, NestingSet:\n\t\t\tif a.NestedType.Nesting == NestingSet {\n\t\t\t\tety := a.ImpliedType()\n\t\t\t\tif ety.HasDynamicTypes() {\n\t\t\t\t\t// This is not permitted because the HCL (cty) set implementation\n\t\t\t\t\t// needs to know the exact type of set elements in order to\n\t\t\t\t\t// properly hash them, and so can't support mixed types.\n\t\t\t\t\terr = errors.Join(err, fmt.Errorf(\"%s%s: NestingSet attributes may not contain attributes of cty.DynamicPseudoType\", prefix, name))\n\t\t\t\t}\n\t\t\t\tif a.NestedType.ContainsWriteOnly() {\n\t\t\t\t\t// This is not permitted because any marks within sets will","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/configs/configschema/internal_validate.go#L147-L183","documentation":"Thrown by Attribute.internalValidate when a provider/schema attribute defines both a Type (a primitive/collection cty type) and a NestedType (a block-style nested object). The schema model is mutually exclusive: an attribute is either a flat value of Type or a nested block described by NestedType, never both. Note this specific call uses errors.Join without the prior err accumulator, so on this branch earlier collected errors are dropped (likely a latent bug), but the trigger condition itself is genuine.","triggerScenarios":"Building a *configschema.Attribute where both Attribute.Type is set (e.g. cty.String) and Attribute.NestedType is non-nil, then calling InternalValidate() on the containing Block/Object (which recurses into internalValidate). Typical in Terraform plugin SDK/terraform-plugin-framework schema conversion or hand-built schemas in tests.","commonSituations":"Migrating a provider schema between SDK v1 (Type) and terraform-plugin-framework (NestedType/Blocks) and forgetting to clear the old field; copy-pasting an attribute definition and adding a NestedType while leaving Type populated; converting a list-of-objects attribute represented as Type=cty.List(...) into a NestedType=NestingList block without removing Type.","solutions":["Inspect the offending attribute named in the error and pick one representation: keep Type for a scalar/list/map/set value OR keep NestedType for a nested block — not both.","If you intended a nested block, set Attribute.Type = cty.NilType (leave it unset) and populate only Attribute.NestedType.","If you intended a typed collection value (e.g. list of objects as a single value), drop NestedType and express the element shape inside Type, e.g. cty.List(cty.Object(...)).","Add a unit test that calls schema.InternalValidate() / block.InternalValidate() right after construction so this fails at build time instead of runtime."],"exampleFix":"// before\nattr := &configschema.Attribute{\n    Type: cty.List(cty.String),\n    NestedType: &configschema.Object{\n        Nesting: configschema.NestingList,\n        Attributes: map[string]*configschema.Attribute{...},\n    },\n    Optional: true,\n}\n\n// after — choose nested block form\nattr := &configschema.Attribute{\n    NestedType: &configschema.Object{\n        Nesting: configschema.NestingList,\n        Attributes: map[string]*configschema.Attribute{...},\n    },\n    Optional: true,\n}","handlingStrategy":"validation","validationCode":"// Run before InternalValidate on any hand-built schema.\nfunc assertTypeXORNestedType(a *configschema.Attribute) error {\n    if a.Type != cty.NilType && a.NestedType != nil {\n        return fmt.Errorf(\"attribute cannot set both Type and NestedType\")\n    }\n    if a.Type == cty.NilType && a.NestedType == nil {\n        return fmt.Errorf(\"attribute must set either Type or NestedType\")\n    }\n    return nil\n}","typeGuard":"func isBlockAttribute(a *configschema.Attribute) bool {\n    return a != nil && a.Type == cty.NilType && a.NestedType != nil\n}","tryCatchPattern":null,"preventionTips":["Always construct Attributes through a small factory that takes either a Type or a *Object, never both.","Call InternalValidate() in every provider unit test so mis-configured schemas fail at test time, not runtime.","During SDK-to-framework migration, grep for 'Type:' alongside 'NestedType:' in the same literal to catch leftovers."],"tags":["schema-validation","configschema","terraform-provider","go"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}