hashicorp/terraform · error
Must provide one of 'source' or 'content'
Error message
Must provide one of 'source' or 'content'
What it means
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.
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).
Example fix
# before
provisioner "file" {
destination = "/etc/app/app.conf"
}
# after
provisioner "file" {
content = "key=value"
destination = "/etc/app/app.conf"
} Defensive patterns
Strategy: validation
Validate before calling
func validateFileProvisioner(src, content string) error {
if src == "" && content == "" {
return errors.New("Must provide one of 'source' or 'content'")
}
return nil
} Type guard
func hasPayload(src, content cty.Value) bool {
return !src.IsNull() || !content.IsNull()
} Prevention
- 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.
When it happens
Trigger: A provisioner "file" block that sets only `destination` (and maybe connection {}) but omits both `source` and `content`, triggering the second switch case in ValidateProvisionerConfig.
Common situations: Writing a file provisioner block and forgetting the payload attribute. Using a variable for content/source that resolves to null.
Related errors
- Cannot set both 'source' and 'content'
- host for provisioner cannot be empty
- invalid empty string in 'script'
- invalid empty string in 'scripts'
- invalid null string in 'script'
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/08591432c6a06487.
Report an issue: GitHub.
Appendix: source
Thrown at internal/builtin/provisioners/file/resource_provisioner.go:72
resp.Provisioner = schema
return resp
}
func (p *provisioner) ValidateProvisionerConfig(req provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {
cfg, err := p.GetSchema().Provisioner.CoerceValue(req.Config)
if err != nil {
resp.Diagnostics = resp.Diagnostics.Append(err)
}
source := cfg.GetAttr("source")
content := cfg.GetAttr("content")
switch {
case !source.IsNull() && !content.IsNull():
resp.Diagnostics = resp.Diagnostics.Append(errors.New("Cannot set both 'source' and 'content'"))
return resp
case source.IsNull() && content.IsNull():
resp.Diagnostics = resp.Diagnostics.Append(errors.New("Must provide one of 'source' or 'content'"))
return resp
}
return resp
}
func (p *provisioner) ProvisionResource(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
if req.Connection.IsNull() {
resp.Diagnostics = resp.Diagnostics.Append(tfdiags.WholeContainingBody(
tfdiags.Error,
"file provisioner error",
"Missing connection configuration for provisioner.",
))
return resp
}
comm, err := communicator.New(req.Connection)
if err != nil {View on GitHub (pinned to d32a084675)