{"record":{"id":"08591432c6a06487","repo":"hashicorp/terraform","slug":"must-provide-one-of-source-or-content","errorCode":null,"errorMessage":"Must provide one of 'source' or 'content'","messagePattern":"Must provide one of 'source' or 'content'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/builtin/provisioners/file/resource_provisioner.go","lineNumber":72,"sourceCode":"\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}\n\n\tcomm, err := communicator.New(req.Connection)\n\tif err != nil {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/builtin/provisioners/file/resource_provisioner.go#L54-L90","documentation":"Validation diagnostic from the 'file' provisioner when both 'source' and 'content' are null. Because 'destination' is Required but the payload to copy is missing, the provisioner has nothing to transfer.","triggerScenarios":"A provisioner \"file\" block omits both 'source' and 'content', or sets them both to null via a variable whose value is empty.","commonSituations":"Conditionally setting source/content through a variable that resolves to null; leftover placeholder block during refactoring.","solutions":["Provide exactly one of 'source' (path to a local file) or 'content' (inline string).","If the file provisioner is optional, use a dynamic/count = 0 block instead of leaving both fields null."],"exampleFix":"// before\nprovisioner \"file\" {\n  destination = \"/etc/app.conf\"\n}\n// after\nprovisioner \"file\" {\n  content     = \"raw config\"\n  destination = \"/etc/app.conf\"\n}","handlingStrategy":"validation","validationCode":"# Ensure at least one of source/content is provided:\nterraform validate\n# For dynamic provisioners, gate on the variable being set:\n# dynamic \"provisioner\" { for_each = var.content == null ? [] : [1] ... }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default variables used for source/content to a concrete value, not null.","Use count = 0 on the resource when the provisioner has nothing to copy.","Validate configuration in CI before provisioning."],"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"}