walkor/workerman · error · RuntimeException

Bad worker->transport ${var_export($this->transport, true)}

Error message

Bad worker->transport ${var_export($this->transport, true)}

What it means

When the socketName uses a non-builtin scheme (a custom protocol class), parseSocketAddress() also validates $worker->transport against Worker::BUILD_IN_TRANSPORTS = ['tcp','udp','unix','ssl']. An unknown transport value throws this exception with the var_export'd value, because the transport decides which low-level socket gets created (BUILD_IN_TRANSPORTS[$this->transport] . ':' . $address would otherwise index a missing key).

Source

Thrown at src/Worker.php:2574

        // Get the application layer communication protocol and listening address.
        [$scheme, $address] = explode(':', $this->socketName, 2);
        // Check application layer protocol class.
        if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) {
            // Validate scheme contains only safe characters for class name resolution.
            if (!preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $scheme)) {
                throw new RuntimeException("Invalid protocol scheme '$scheme'");
            }
            $scheme = ucfirst($scheme);
            $this->protocol = 'Protocols\\' . $scheme;
            if (!class_exists($this->protocol)) {
                $this->protocol = "Workerman\\Protocols\\$scheme";
                if (!class_exists($this->protocol)) {
                    throw new RuntimeException("class \\Protocols\\$scheme not exist");
                }
            }

            if (!isset(self::BUILD_IN_TRANSPORTS[$this->transport])) {
                throw new RuntimeException('Bad worker->transport ' . var_export($this->transport, true));
            }
        } else if ($this->transport === 'tcp') {
            $this->transport = $scheme;
        }
        //local socket
        return self::BUILD_IN_TRANSPORTS[$this->transport] . ":" . $address;
    }

    /**
     * Pause accept new connections.
     *
     * @return void
     */
    public function pauseAccept(): void
    {
        if (static::$globalEvent !== null && !$this->pauseAccept && $this->mainSocket !== null) {
            static::$globalEvent->offReadable($this->mainSocket);
            $this->pauseAccept = true;

View on GitHub (pinned to 1391112a61)

Solutions

  1. Set the transport to a legal value: `$worker->transport = 'tcp';` (use 'udp', 'unix', or 'ssl' as appropriate).
  2. If you wanted websocket/http, drop the custom transport and put it in the listen address instead: `new Worker('ws://0.0.0.0:8080')` or `new Worker('http://0.0.0.0:8080')`.
  3. For TLS with a custom text protocol, keep transport='ssl' and configure $worker->transport context with local_cert/local_pk.
  4. If the transport comes from config, validate/case-normalize it before assigning.

Example fix

// before: 'websocket' is not a transport
$worker = new Worker('myProto://0.0.0.0:8080');
$worker->transport = 'websocket';

// after: keep the transport low-level; express the protocol in the scheme
$worker = new Worker('MyProto://0.0.0.0:8080');
$worker->transport = 'tcp';
Defensive patterns

Strategy: validation

Validate before calling

$transport = strtolower((string)$config['transport']);
if (!in_array($transport, array_keys(Workerman\Worker::BUILD_IN_TRANSPORTS), true)) {
    throw new InvalidArgumentException(
        "transport must be one of tcp|udp|unix|ssl, got '{$config['transport']}'"
    );
}
$worker->transport = $transport;

Type guard

function isBuiltinTransport(string $transport): bool
{
    return isset(Workerman\Worker::BUILD_IN_TRANSPORTS[$transport]);
}

Prevention

When it happens

Trigger: Setting $worker->transport to anything outside tcp/udp/unix/ssl while using a custom scheme — e.g. $worker->transport = 'websocket' (not a transport; the scheme 'ws://' handles that), 'tcp6', 'http', 'Text', or null/int from a config variable.

Common situations: Confusing the application-layer protocol with the transport: writing transport='websocket' or 'http' instead of using the ws:// or http:// scheme in the listen address; loading transport from an env/config file with a typo or wrong casing; upgrading old configs that used arbitrary strings.

Related errors


AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21). Data as JSON: /api/errors/f2e735f2640aa43f. Report an issue: GitHub.