SFTP uses SSH as transport. Any SFTP client expects the SSH server to establish communication with an SFTP server (like sftp-server).
At least with OpenSSH, when an SSH server is told to run something, it uses the target user's shell for this.
One can define a subsystem (it may be a custom subsystem) by adding Subsystem … entry in sshd_config. Even then the supplied command will be executed in the user's shell. This happened to you with the standard sftp subsystem specified as /usr/lib/ssh/sftp-server.
If the shell (or anything really) prints some "garbage" when your SFTP client expects to talk to an SFTP server, it's outside of the SFTP protocol and thus the communication breaks.
As long as the SSH server uses the user's shell, no option can totally reliably make everything work. This is because in general:
- The user's shell may be anything.
- Even sane shells source some files. Some shells may be told not to, but there is no portable option for this and there is no way for a client to tell the SSH server to use a custom option when invoking a shell.
- The sourced files may print something; or they may run something that prints something.
The only way to avoid the user's shell is to use a subsystem handled internally by the SSH server. AFAIK for now the only internal subsystem in sshd from OpenSSH is internal-sftp.
internal-sftp solved your problem because it does not rely on a shell.
An alternative fix is to make sure nothing but SFTP server uses the standard streams provided by the SSH server. This solution includes silencing the user's shell and anything the shell starts before it runs the actual requested command like /usr/lib/ssh/sftp-server. A person with root access on the server or the user himself/herself may easily break this.
Some interesting cases, for comparison:
Subsystem sftp /usr/lib/ssh/sftp-serverwhich used to work for you. I hope that someone with a system more similar to yours will see your question and help you find an answer.