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
- Remove empty strings from the inline list, e.g. `inline = [for s in var.cmds : s if s != ""]`.
- 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
- Strip empty strings: [for s in xs : s if s != ""].
- Avoid concatenating lists that can yield empty entries.
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
- invalid empty string in 'script'
- invalid null string in 'script'
- invalid null string in 'scripts'
- Cannot set both 'source' and 'content'
- host for provisioner cannot be empty
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)