{"record":{"id":"a54fea5263870fad","repo":"hashicorp/packer","slug":"error-removing-temporary-script-at-s","errorCode":null,"errorMessage":"Error removing temporary script at %s!","messagePattern":"Error removing temporary script at (.+?)!","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"provisioner/shell/provisioner.go","lineNumber":414,"sourceCode":"\nfunc (p *Provisioner) cleanupRemoteFile(path string, comm packersdk.Communicator) error {\n\tctx := context.TODO()\n\terr := retry.Config{StartTimeout: p.config.StartRetryTimeout}.Run(ctx, func(ctx context.Context) error {\n\t\tcmd := &packersdk.RemoteCmd{\n\t\t\tCommand: fmt.Sprintf(\"rm -f %s\", path),\n\t\t}\n\t\tif err := comm.Start(ctx, cmd); err != nil {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"Error removing temporary script at %s: %s\",\n\t\t\t\tpath, err)\n\t\t}\n\t\tcmd.Wait()\n\t\t// treat disconnects as retryable by returning an error\n\t\tif cmd.ExitStatus() == packersdk.CmdDisconnect {\n\t\t\treturn fmt.Errorf(\"Disconnect while removing temporary script.\")\n\t\t}\n\t\tif cmd.ExitStatus() != 0 {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"Error removing temporary script at %s!\",\n\t\t\t\tpath)\n\t\t}\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (p *Provisioner) escapeEnvVars() ([]string, map[string]string) {\n\tenvVars := make(map[string]string)\n\n\t// Always available Packer provided env vars\n\tenvVars[\"PACKER_BUILD_NAME\"] = p.config.PackerBuildName","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/shell/provisioner.go#L396-L432","documentation":"After the `rm -f` command runs successfully (connection intact), the provisioner checks its exit status; a non-zero status means the remote shell could not delete the temporary script, and this error is raised (and retried by the enclosing retry loop). Because the command is `rm -f`, this usually indicates permission problems on the remote path rather than a missing file.","triggerScenarios":"comm.Start succeeds and cmd.Wait returns, but cmd.ExitStatus() != 0 for `rm -f <path>` — e.g. the file is owned by another user, the directory is not writable, or a shell-level error occurred on the remote host.","commonSituations":"RemotePath placed in a root-owned directory while the SSH user is unprivileged; immutable/read-only filesystem; SELinux or AppArmor policies blocking deletion; path with characters interpreted oddly by the remote shell.","solutions":["Set remote_path to a directory writable by the communicator user (e.g. /tmp/script.sh)","Check remote permissions/ownership of the uploaded file and its directory","Set skip_clean = true if leaving the temp file is harmless for your image","SSH in manually and run `rm -f <path>` to see the underlying shell error"],"exampleFix":"// before\nprovisioner \"shell\" {\n  remote_path = \"/root/packer-shell/script.sh\"\n}\n// after\nprovisioner \"shell\" {\n  remote_path = \"/tmp/packer-shell/script.sh\"\n}","handlingStrategy":"validation","validationCode":"# Ensure the communicator user can delete the remote path:\nssh user@host 'test -w $(dirname /tmp/packer-shell/script.sh) && echo writable'","typeGuard":null,"tryCatchPattern":"if cmd.ExitStatus() != 0 {\n    return fmt.Errorf(\"Error removing temporary script at %s!\", path) // retried, then surfaced\n}","preventionTips":["Choose a remote_path under a directory writable by the SSH/WinRM user","Avoid paths on read-only, immutable, or policy-restricted filesystems","Use skip_clean = true when cleanup failures are harmless","Verify the exact path has no characters that confuse the remote shell"],"tags":["provisioner","shell","cleanup","permissions","exit-code"],"backgroundTag":"remote-command-nonzero-exit","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}