{"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/c9def3e214014c1188faabfc4a5bde5095139765/internal/builtin/provisioners/file/resource_provisioner.go#L51-L87","documentation":"Validation diagnostic from the 'file' provisioner's ValidateProvisionerConfig. The schema declares both 'source' and 'content' as Optional, but they are mutually exclusive; if both are non-null after coercion, this error is emitted and provisioning is aborted.","triggerScenarios":"A resource provisioner block sets both 'source = ...' and 'content = ...' at once, e.g. provisioner \"file\" { source = \"./a\" content = \"x\" destination = \"/b\" }.","commonSituations":"Copy-pasting a provisioner block and forgetting to delete the old argument; templating that conditionally injects both keys.","solutions":["Remove either 'source' or 'content' so exactly one is set.","Use 'content' for inline strings, 'source' to copy an existing local file."],"exampleFix":"// before\nprovisioner \"file\" {\n  source      = \"./app.conf\"\n  content     = \"raw config\"\n  destination = \"/etc/app.conf\"\n}\n// after\nprovisioner \"file\" {\n  content     = \"raw config\"\n  destination = \"/etc/app.conf\"\n}","handlingStrategy":"validation","validationCode":"# Validate the provisioner block has exactly one of source/content before apply:\nterraform validate\n# Or in CI, a custom check (using e.g. tfsh or hclspec) rejecting blocks\n# where both source and content are set.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run 'terraform validate' in CI to catch mutually-exclusive args before apply.","Use a single convention per module (always 'content' or always 'source').","Code-review provisioner blocks for leftover arguments."],"tags":["terraform","provisioner","file","config-validation","hcl"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}