fix(storages): connect to SFTP hosts on IPv6 and show the network error

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-11-10 14:19:42 +01:00
co-authored by Claude Opus 5.5
parent 6bdc780af2
commit 989c2238f8
3 changed files with 18 additions and 1 deletions
@@ -0,0 +1,6 @@
---
type: fixed
---
Failed connection to SFTP backup storages on an IPv6 address, and a connection error without the network reason
- The error now shows the network reason, for example `Connection refused` or `Connection timed out`
+10
View File
@@ -26,6 +26,7 @@ use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use League\Flysystem\Filesystem;
use League\Flysystem\FilesystemAdapter as FlysystemAdapter;
use phpseclib3\Exception\UnableToConnectException;
class S3Storage extends BaseModel
{
@@ -956,6 +957,15 @@ class S3Storage extends BaseModel
private function toUserFriendlyConnectionException(\Throwable $exception): \Throwable
{
$rootCause = $exception;
while ($rootCause->getPrevious() !== null) {
$rootCause = $rootCause->getPrevious();
}
if ($rootCause instanceof UnableToConnectException) {
// Flysystem shows only "Unable to connect to host". The network error (refused, timed out) is in phpseclib.
return new \RuntimeException('Could not connect to the '.$this->storageType()->label().' server: '.$rootCause->getMessage(), previous: $exception);
}
$message = str($exception->getMessage())->lower();
if ($message->contains(['timed out', 'timeout', 'connection refused', 'could not resolve', 'curl error 28'])) {
+2 -1
View File
@@ -29,7 +29,8 @@ class PinnedSftpConnectionProvider implements ConnectionProvider
public static function create(string $host, string $address, int $port, string $username, ?string $password, ?string $privateKey, ?string $pinnedHostKey, int $timeout): self
{
$provider = app(SftpConnectionProvider::class, [
'host' => $address,
// phpseclib passes the host to fsockopen(), which needs brackets around an IPv6 address.
'host' => filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false ? "[{$address}]" : $address,
'username' => $username,
'password' => $password,
'privateKey' => $privateKey,