kopia/kopia · error
error creating sftp client pipe
Error message
error creating sftp client pipe
What it means
errors.Wrap around sftp.NewClientPipe(rd, wr) in getSFTPClientExternal. The SSH subprocess started, but the SFTP subsystem handshake over its stdin/stdout pipes failed — the remote side likely did not run an SFTP server, closed the pipe, or returned a protocol error. kopia closes the process (closeFunc) before returning this error to avoid leaking the spawned ssh process.
Solutions
- Verify the remote sshd has an sftp subsystem: check 'Subsystem sftp internal-sftp' (or sftp-server path) in /etc/ssh/sshd_config on the server.
- Test manually with 'ssh user@host -s sftp' — if it fails or prints garbage, fix server-side SFTP config first.
- Confirm credentials/key auth work for a plain ssh login; add -i <keyfile> or correct user to the sftp.command option.
- Check the remote server logs (auth.log) for why the SFTP subsystem request was rejected (fail2ban, MaxStartups, disabled user).
Example fix
// before (server sshd_config) # Subsystem sftp internal-sftp // commented out -> pipe handshake fails // after Subsystem sftp internal-sftp
Defensive patterns
Strategy: validation
Validate before calling
out, err := exec.Command("ssh", "-o", "BatchMode=yes", host, "-s", "sftp").CombinedOutput()
if err != nil { return fmt.Errorf("sftp subsystem unavailable on %s: %v: %s", host, err, out) } Try / catch
conn, err := storage.NewSFTP(ctx, opts)
if err != nil && strings.Contains(err.Error(), "error creating sftp client pipe") {
// handshake failed: verify remote sftp subsystem and credentials
return fmt.Errorf("remote SFTP subsystem rejected the session: %w", err)
} Prevention
- Confirm 'Subsystem sftp internal-sftp' exists in the server's sshd_config.
- Test 'ssh user@host -s sftp' manually before configuring kopia.
- Use BatchMode key auth to avoid banner/prompt output corrupting the pipe protocol.
- Keep fail2ban/MaxStartups from blocking repeated connections.
When it happens
Trigger: sftp.NewClientPipe(rd, wr) fails because the remote sshd has no sftp subsystem enabled, the sftp server binary path in the ssh command is wrong, authentication failed, or the process died immediately after Start.
Common situations: Remote server's sshd_config lacks 'Subsystem sftp internal-sftp' (or points to a missing sftp-server binary); wrong username/password/key; server closed connection due to MaxStartups or fail2ban; custom SSH wrappers that print banners breaking the protocol stream.
Related errors
- error closing SFTP client
- error closing SFTP connection
- error starting SSH
- key file path must be absolute
- known hosts path must be absolute
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/412480bab61ced33.
Report an issue: GitHub.
Appendix: source
Thrown at repo/blob/sftp/sftp_storage.go:504
if err = cmd.Start(); err != nil {
return nil, errors.Wrap(err, "error starting SSH")
}
closeFunc := func() error {
p := cmd.Process
if p != nil {
p.Kill() //nolint:errcheck
}
return nil
}
// open the SFTP session
c, err := sftp.NewClientPipe(rd, wr)
if err != nil {
closeFunc() //nolint:errcheck
return nil, errors.Wrap(err, "error creating sftp client pipe")
}
return &sftpConnection{
currentClient: c,
closeFunc: closeFunc,
}, nil
}
func getSFTPClient(ctx context.Context, opt *Options) (*sftpConnection, error) {
if opt.ExternalSSH {
return getSFTPClientExternal(ctx, opt)
}
config, err := createSSHConfig(ctx, opt)
if err != nil {
return nil, err
}
View on GitHub (pinned to 82495e54b5)