{"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/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/builtin/provisioners/file/resource_provisioner.go#L54-L90","documentation":"Thrown by the file provisioner's ValidateProvisionerConfig (resource_provisioner.go:72) when neither `source` nor `content` is set. The provisioner requires exactly one of the two so it knows what to copy; with both null it has nothing to transfer, so validation fails immediately.","triggerScenarios":"A provisioner \"file\" block that sets only `destination` (and maybe connection {}) but omits both `source` and `content`, triggering the second switch case in ValidateProvisionerConfig.","commonSituations":"Writing a file provisioner block and forgetting the payload attribute. Using a variable for content/source that resolves to null.","solutions":["Add exactly one of `source = \"<local path>\"` or `content = \"<inline string>\"` to the file provisioner block.","If the value is variable-driven, ensure the variable is non-null (use a default or coalesce)."],"exampleFix":"# before\nprovisioner \"file\" {\n  destination = \"/etc/app/app.conf\"\n}\n# after\nprovisioner \"file\" {\n  content     = \"key=value\"\n  destination = \"/etc/app/app.conf\"\n}","handlingStrategy":"validation","validationCode":"func validateFileProvisioner(src, content string) error {\n    if src == \"\" && content == \"\" {\n        return errors.New(\"Must provide one of 'source' or 'content'\")\n    }\n    return nil\n}","typeGuard":"func hasPayload(src, content cty.Value) bool {\n    return !src.IsNull() || !content.IsNull()\n}","tryCatchPattern":null,"preventionTips":["Always specify exactly one of source or content in the file provisioner.","Run terraform validate to surface this during the validation phase.","Give payload variables non-null defaults."],"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"}