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

  1. 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.
  2. Test manually with 'ssh user@host -s sftp' — if it fails or prints garbage, fix server-side SFTP config first.
  3. Confirm credentials/key auth work for a plain ssh login; add -i <keyfile> or correct user to the sftp.command option.
  4. 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

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


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)