thephpleague/flysystem · error · UnableToMakeConnectionPassive

Could not set passive mode for connection

Error message

Could not set passive mode for connection: {host}::{port}

What it means

FtpConnectionProvider::makeConnectionPassive() calls ftp_pasv() with the 'passive' option value; if the FTP extension reports failure, UnableToMakeConnectionPassive is thrown with 'Could not set passive mode for connection: host::port'. ftp_pasv only sets the transfer-mode preference, but it fails when the connection is broken or the server rejects the PASV setup during handshake, and Flysystem treats it as fatal.

Solutions

  1. Open the server's passive port range (e.g. 50000-51000) in the FTP server config AND the firewall, and set matching PassivePortRange on the server.
  2. If the server/network requires active mode, set 'passive' => false in FtpConnectionOptions.
  3. Verify basic PASV transfers with an FTP CLI client from the same host/network namespace to isolate app vs environment.
  4. Catch UnableToMakeConnectionPassive and retry once — transient control-connection drops can surface here.

Example fix

// before
$options = FtpConnectionOptions::lazy('ftp.example.com', '/', FTP_NATIVE, null, 'u', 'p', null, true /* passive */);
$filesystem->read('file.txt'); // ftp_pasv fails -> throws

// after (active mode environment)
$options = FtpConnectionOptions::lazy('ftp.example.com', '/', FTP_NATIVE, null, 'u', 'p', null, false /* active */);
Defensive patterns

Strategy: retry

Validate before calling

// No in-code pre-check possible for ftp_pasv, but you can pre-flight connectivity:
// ensure the server's passive port range is reachable from the app host
$socket = @fsockopen($host, 50000, $errno, $errstr, 3); // first port of the declared range
if ($socket === false) {
    // passive data channel blocked: fix firewall/NAT before runtime failures
}
fclose($socket);

Try / catch

use League\Flysystem\Ftp\UnableToMakeConnectionPassive;

$maxAttempts = 2;
for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
    try {
        return $filesystem->read($path);
    } catch (UnableToMakeConnectionPassive $e) {
        if ($attempt === $maxAttempts) {
            // persistent: likely firewall/active-mode mismatch — switch strategy, don't loop
            $options = FtpConnectionOptions::lazy($host, '/', FTP_NATIVE, null, $user, $pass, null, false);
            $filesystem = new Filesystem(new FtpAdapter($options));
        }
    }
}

Prevention

When it happens

Trigger: First file operation after connect when passive = true and the server/firewall interferes with the PASV command (some servers reject PASV before authentication or when data connections are blocked); the control connection dropped between login and pasv; ftp_pasv returning false on servers behind broken NAT.

Common situations: Firewalls between app and FTP server blocking the passive data port range; servers that require active mode (passive = false) but the option was left true; containerized apps where the FTP module cannot negotiate data connections.

Related errors


AI-assisted analysis of thephpleague/flysystem@b277b5dc3d (2026-08-17). Data as JSON: /api/errors/a16cf4c64aacb027. Report an issue: GitHub.

Appendix: source

Thrown at src/Ftp/FtpConnectionProvider.php:105

    {
        $ignorePassiveAddress = $options->ignorePassiveAddress();

        if ( ! is_bool($ignorePassiveAddress) || ! defined('FTP_USEPASVADDRESS')) {
            return;
        }

        if ( ! @ftp_set_option($connection, FTP_USEPASVADDRESS, ! $ignorePassiveAddress)) {
            throw UnableToSetFtpOption::whileSettingOption('FTP_USEPASVADDRESS');
        }
    }

    /**
     * @param resource $connection
     */
    private function makeConnectionPassive(FtpConnectionOptions $options, $connection): void
    {
        if ( ! @ftp_pasv($connection, $options->passive())) {
            throw new UnableToMakeConnectionPassive(
                'Could not set passive mode for connection: ' . $options->host() . '::' . $options->port()
            );
        }
    }
}

View on GitHub (pinned to b277b5dc3d)