{"record":{"id":"c32cfd69f66929db","repo":"hashicorp/packer","slug":"disconnect-while-removing-temporary-script","errorCode":null,"errorMessage":"Disconnect while removing temporary script.","messagePattern":"Disconnect while removing temporary script\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"provisioner/shell/provisioner.go","lineNumber":411,"sourceCode":"\n\treturn nil\n}\n\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)","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/shell/provisioner.go#L393-L429","documentation":"Inside the cleanup retry loop, if the `rm -f` command's exit status is CmdDisconnect (2300218), the provisioner returns this error so the surrounding retry.Config loop treats the disconnect as retryable and re-attempts the removal until StartRetryTimeout expires. It is an internal retry signal, surfaced to the user only if retries are exhausted.","triggerScenarios":"The remote command `rm -f <path>` completes with the disconnect sentinel exit status — typically because the machine rebooted (script-triggered) or the connection dropped while cleanup ran.","commonSituations":"Shell scripts that reboot the machine, causing cleanup to race the reboot; unstable network to the instance at end of provisioning; hosts that terminate sessions aggressively.","solutions":["Give the retry more room: increase start_retry_timeout so cleanup survives the reboot window","Set skip_clean = true to skip remote file cleanup entirely when acceptable","Ensure scripts finish any reboot and the machine is reachable before provisioning ends","Investigate the underlying connection instability (keepalives, security groups, sshd settings)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Cleanup already treats disconnects as retryable:\nerr := retry.Config{StartTimeout: p.config.StartRetryTimeout}.Run(ctx, func(ctx context.Context) error {\n    if cmd.ExitStatus() == packersdk.CmdDisconnect {\n        return fmt.Errorf(\"Disconnect while removing temporary script.\") // retry signal\n    }\n    return nil\n})","preventionTips":["Increase start_retry_timeout to cover the full reboot window after disconnecting scripts","Set skip_clean = true to avoid cleanup races entirely","Sequence rebooting scripts so cleanup runs after the machine is back","Monitor for repeated disconnects indicating network/sshd instability"],"tags":["provisioner","shell","cleanup","disconnect","retry"],"backgroundTag":"unexpected-remote-disconnect","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"}