hashicorp/terraform · error

invalid empty string in 'scripts'

Error message

invalid empty string in 'scripts'

What it means

Thrown by remote-exec generateScripts (resource_provisioner.go:163) when an `inline` element is a non-null but empty string (""). Each inline command must have content; an empty element would inject a blank line into the generated script, so the provisioner rejects it.

Solutions

  1. Remove empty strings from the inline list, e.g. `inline = [for s in var.cmds : s if s != ""]`.
  2. Ensure each inline element is a real command string.

Example fix

# before
provisioner "remote-exec" {
  inline = ["echo hi", "", "echo bye"]
}
# after
provisioner "remote-exec" {
  inline = ["echo hi", "echo bye"]
}
Defensive patterns

Strategy: validation

Validate before calling

func inlineHasNoEmpty(xs []string) error {
    for _, s := range xs {
        if s == "" { return errors.New("invalid empty string in 'scripts'") }
    }
    return nil
}

Type guard

func inlineAllNonEmpty(v cty.Value) bool {
    for _, e := range v.AsValueSlice() {
        if !e.IsNull() && e.AsString() == "" { return false }
    }
    return true
}

Prevention

When it happens

Trigger: A provisioner "remote-exec" block whose `inline` list contains "", e.g. `inline = ["echo hi", "", "echo bye"]`, hitting the `s == ""` branch.

Common situations: Trailing/leading empty strings from list concatenation. Variables that default to "" and are appended unconditionally.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/550abeecf3ee7d2c. Report an issue: GitHub.

Appendix: source

Thrown at internal/builtin/provisioners/remote-exec/resource_provisioner.go:163

	p.cancel()
	return nil
}

func (p *provisioner) Close() error {
	return nil
}

// generateScripts takes the configuration and creates a script from each inline config
func generateScripts(inline cty.Value) ([]string, error) {
	var lines []string
	for _, l := range inline.AsValueSlice() {
		if l.IsNull() {
			return nil, errors.New("invalid null string in 'scripts'")
		}

		s := l.AsString()
		if s == "" {
			return nil, errors.New("invalid empty string in 'scripts'")
		}
		lines = append(lines, s)
	}
	lines = append(lines, "")

	return []string{strings.Join(lines, "\n")}, nil
}

// collectScripts is used to collect all the scripts we need
// to execute in preparation for copying them.
func collectScripts(v cty.Value) ([]io.ReadCloser, error) {
	// Check if inline
	if inline := v.GetAttr("inline"); !inline.IsNull() {
		scripts, err := generateScripts(inline)
		if err != nil {
			return nil, err
		}

View on GitHub (pinned to d32a084675)