{"record":{"id":"3fbce8ad65611280","repo":"hashicorp/terraform","slug":"error-reading-script-s","errorCode":null,"errorMessage":"Error reading script: %s","messagePattern":"Error reading script: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/communicator/ssh/communicator.go","lineNumber":451,"sourceCode":"\t}\n\n\tscpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {\n\t\treturn scpUploadFile(targetFile, input, w, stdoutR, size)\n\t}\n\n\tcmd, err := quoteScpCommand([]string{\"scp\", \"-vt\", targetDir}, c.connInfo.TargetPlatform)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn c.scpSession(cmd, scpFunc)\n}\n\n// UploadScript implementation of communicator.Communicator interface\nfunc (c *Communicator) UploadScript(path string, input io.Reader) error {\n\treader := bufio.NewReader(input)\n\tprefix, err := reader.Peek(2)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Error reading script: %s\", err)\n\t}\n\tvar script bytes.Buffer\n\n\tif string(prefix) != \"#!\" && c.connInfo.TargetPlatform != TargetPlatformWindows {\n\t\tscript.WriteString(DefaultShebang)\n\t}\n\tscript.ReadFrom(reader)\n\n\tif err := c.Upload(path, &script); err != nil {\n\t\treturn err\n\t}\n\tif c.connInfo.TargetPlatform != TargetPlatformWindows {\n\t\tvar stdout, stderr bytes.Buffer\n\t\tcmd := &remote.Cmd{\n\t\t\tCommand: fmt.Sprintf(\"chmod 0777 %s\", path),\n\t\t\tStdout:  &stdout,\n\t\t\tStderr:  &stderr,\n\t\t}","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/communicator/ssh/communicator.go#L433-L469","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nscript := bytes.NewReader(nil) // empty reader\ncomm.UploadScript(path, script)\n\n// after\nscript := bytes.NewReader([]byte(\"#!/bin/sh\\necho hello\\n\"))\ncomm.UploadScript(path, script)","handlingStrategy":"validation","validationCode":"// Validate the script reader is non-empty before calling UploadScript\nfunc validateScriptReader(r io.Reader) error {\n    data, err := io.ReadAll(r)\n    if err != nil {\n        return fmt.Errorf(\"cannot read script: %w\", err)\n    }\n    if len(data) < 2 {\n        return errors.New(\"script content is empty or too short\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["ssh","script-upload","io-reader","terraform"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}