hashicorp/terraform · error
Error reading script: %s
Error message
Error reading script: %s
What it means
Raised in Communicator.UploadScript when reader.Peek(2) fails while inspecting the first two bytes of the script input to detect a shebang (#!) prefix. The SSH communicator peeks at the script body before uploading so it can inject DefaultShebang (#!/bin/sh) on unix targets if no shebang is present. A failure here means the input io.Reader could not supply even two bytes, typically because it is empty or already exhausted.
Source
Thrown at internal/communicator/ssh/communicator.go:451
}
scpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {
return scpUploadFile(targetFile, input, w, stdoutR, size)
}
cmd, err := quoteScpCommand([]string{"scp", "-vt", targetDir}, c.connInfo.TargetPlatform)
if err != nil {
return err
}
return c.scpSession(cmd, scpFunc)
}
// UploadScript implementation of communicator.Communicator interface
func (c *Communicator) UploadScript(path string, input io.Reader) error {
reader := bufio.NewReader(input)
prefix, err := reader.Peek(2)
if err != nil {
return fmt.Errorf("Error reading script: %s", err)
}
var script bytes.Buffer
if string(prefix) != "#!" && c.connInfo.TargetPlatform != TargetPlatformWindows {
script.WriteString(DefaultShebang)
}
script.ReadFrom(reader)
if err := c.Upload(path, &script); err != nil {
return err
}
if c.connInfo.TargetPlatform != TargetPlatformWindows {
var stdout, stderr bytes.Buffer
cmd := &remote.Cmd{
Command: fmt.Sprintf("chmod 0777 %s", path),
Stdout: &stdout,
Stderr: &stderr,
}View on GitHub (pinned to c9def3e214)
Solutions
- Ensure the script content passed to the provisioner is non-empty and the io.Reader is freshly created (not previously read).
- If using inline scripts, verify the script block contains at least one command line.
- If uploading from a file, confirm the file exists and is non-empty before passing its reader.
Example fix
// before
script := bytes.NewReader(nil) // empty reader
comm.UploadScript(path, script)
// after
script := bytes.NewReader([]byte("#!/bin/sh\necho hello\n"))
comm.UploadScript(path, script) Defensive patterns
Strategy: validation
Validate before calling
// Validate the script reader is non-empty before calling UploadScript
func validateScriptReader(r io.Reader) error {
data, err := io.ReadAll(r)
if err != nil {
return fmt.Errorf("cannot read script: %w", err)
}
if len(data) < 2 {
return errors.New("script content is empty or too short")
}
return nil
} Prevention
- Always create a fresh io.Reader for script content immediately before passing it to UploadScript.
- Avoid passing nil or already-consumed readers to Upload methods.
- Use bytes.NewReader with the full script content for deterministic behavior.
When it happens
Trigger: Calling UploadScript with a nil, empty, zero-length, or already-consumed io.Reader. This occurs when a provisioner passes a bytes.Reader that has been fully read, an empty *os.File, or a reader whose underlying stream was closed before the upload began.
Common situations: A terraform remote-exec provisioner whose inline script is empty, a file() interpolation that resolved to an empty string, or a reader being consumed earlier in the pipeline before being passed to UploadScript.
Related errors
- Error chmodding script file to 0777 in remote machine: %s
- Upload failed: %v
- Failed to upload script: %v
- Error starting script: %v
- connection type '%s' not supported
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/3fbce8ad65611280.
Report an issue: GitHub.