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

  1. Add exactly one of `source = "<local path>"` or `content = "<inline string>"` to the file provisioner block.
  2. 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

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


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)