{"record":{"id":"51edd95951ef778b","repo":"hashicorp/terraform","slug":"cannot-set-both-source-and-content","errorCode":null,"errorMessage":"Cannot set both 'source' and 'content'","messagePattern":"Cannot set both 'source' and 'content'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/builtin/provisioners/file/resource_provisioner.go","lineNumber":69,"sourceCode":"\t\t\t},\n\t\t},\n\t}\n\tresp.Provisioner = schema\n\treturn resp\n}\n\nfunc (p *provisioner) ValidateProvisionerConfig(req provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {\n\tcfg, err := p.GetSchema().Provisioner.CoerceValue(req.Config)\n\tif err != nil {\n\t\tresp.Diagnostics = resp.Diagnostics.Append(err)\n\t}\n\n\tsource := cfg.GetAttr(\"source\")\n\tcontent := cfg.GetAttr(\"content\")\n\n\tswitch {\n\tcase !source.IsNull() && !content.IsNull():\n\t\tresp.Diagnostics = resp.Diagnostics.Append(errors.New(\"Cannot set both 'source' and 'content'\"))\n\t\treturn resp\n\tcase source.IsNull() && content.IsNull():\n\t\tresp.Diagnostics = resp.Diagnostics.Append(errors.New(\"Must provide one of 'source' or 'content'\"))\n\t\treturn resp\n\t}\n\n\treturn resp\n}\n\nfunc (p *provisioner) ProvisionResource(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {\n\tif req.Connection.IsNull() {\n\t\tresp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(\n\t\t\ttfdiags.Error,\n\t\t\t\"file provisioner error\",\n\t\t\t\"Missing connection configuration for provisioner.\",\n\t\t))\n\t\treturn resp\n\t}","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/builtin/provisioners/file/resource_provisioner.go#L51-L87","documentation":"Thrown by the file provisioner's ValidateProvisionerConfig (resource_provisioner.go:69). The file provisioner copies a single file/dir from a local 'source' OR writes inline 'content'; both arguments are mutually exclusive. If both source and content are non-null in the provisioner block, validation appends this error and returns immediately, failing the config validation phase before any apply.","triggerScenarios":"A provisioner \"file\" block whose HCL sets both `source = ...` and `content = ...`. The coercion is done via the provisioner schema; cfg.GetAttr(\"source\") and cfg.GetAttr(\"content\") are both non-null, hitting the first switch case.","commonSituations":"Copy-pasting examples that combine a source path with inline content. Refactoring a file provisioner from source-based to content-based and forgetting to remove the old attribute.","solutions":["Remove either the `source` or the `content` argument from the provisioner block so exactly one is set.","If you need both behaviors, split into two separate file provisioner blocks."],"exampleFix":"# before\nprovisioner \"file\" {\n  source  = \"./app.conf\"\n  content = \"key=value\"\n  destination = \"/etc/app/app.conf\"\n}\n# after\nprovisioner \"file\" {\n  source      = \"./app.conf\"\n  destination = \"/etc/app/app.conf\"\n}","handlingStrategy":"validation","validationCode":"// Before applying, validate the file provisioner sets exactly one payload source.\nfunc validateFileProvisioner(src, content string) error {\n    if src != \"\" && content != \"\" {\n        return errors.New(\"Cannot set both 'source' and 'content'\")\n    }\n    return nil\n}","typeGuard":"type fileProvisionerArgs struct {\n    Source      optional[string]\n    Content     optional[string]\n    Destination string\n}\nfunc (a fileProvisionerArgs) valid() bool {\n    return a.Destination != \"\" && a.Source.set != a.Content.set // exactly one\n}","tryCatchPattern":null,"preventionTips":["Run terraform validate before apply so the provisioner's ValidateProvisionerConfig catches mutual-exclusion errors.","Never set both source and content in a file provisioner block."],"tags":["terraform","provisioner","file-provisioner","validation","config"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}