walkor/workerman · error · RuntimeException
class \Protocols\$scheme not exist
Error message
class \Protocols\$scheme not exist
What it means
The scheme was alphanumeric but is not a built-in transport, so Workerman tried to load an application-layer protocol class: first '\Protocols\<Scheme>' then '\Workerman\Protocols\<Scheme>'. Neither could be autoloaded, so the constructor aborts. This is how workerman resolves schemes like http, ws, text, frame and any user-defined protocol.
Source
Thrown at src/Connection/AsyncTcpConnection.php:222
: $this->remoteHost . ':' . $this->remotePort;
}
$this->id = $this->realId = self::$idRecorder++;
if (PHP_INT_MAX === self::$idRecorder) {
self::$idRecorder = 0;
}
// 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");
}
}
} else {
$this->transport = self::BUILD_IN_TRANSPORTS[$scheme];
}
// For statistics.
++self::$statistics['connection_count'];
$this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
$this->maxPackageSize = self::$defaultMaxPackageSize;
$this->socketContext = $socketContext;
static::$connections[$this->realId] = $this;
$this->context = new stdClass;
}
/**
* Reconnect.
*View on GitHub (pinned to 1391112a61)
Solutions
- Create the protocol class, e.g. Protocols/Myproto.php with namespace Protocols and class Myproto implementing the protocol interface (input/output methods)
- Make sure composer.json autoloads the namespace: "autoload": {"psr-4": {"Protocols\\": "Protocols/"}} and run 'composer dump-autoload'
- If you meant a stock protocol, use its exact scheme: http://, ws://, text://, frame://
Example fix
// before
// config: 'myproto://127.0.0.1:9000' but no class exists
$conn = new AsyncTcpConnection('myproto://127.0.0.1:9000'); // throws class \Protocols\Myproto not exist
// after
// Protocols/Myproto.php
namespace Protocols;
class Myproto
{
public static function input(string $buffer, $connection): int { /* ... */ return strlen($buffer); }
public static function decode(string $buffer, $connection) { return $buffer; }
public static function encode($data, $connection): string { return (string)$data; }
}
// composer.json: "autoload": {"psr-4": {"Protocols\\": "Protocols/"}} then: composer dump-autoload Defensive patterns
Strategy: validation
Validate before calling
$scheme = 'myproto'; // from config
$builtin = ['tcp','udp','unix','ssl','sslv2','sslv3','tls'];
$known = in_array(strtolower($scheme), $builtin, true)
|| class_exists('\\Protocols\\' . ucfirst($scheme))
|| class_exists('\\Workerman\\Protocols\\' . ucfirst($scheme));
if (!$known) {
throw new InvalidArgumentException("Protocol '$scheme' has no class; define Protocols\\" . ucfirst($scheme));
}
$conn = new AsyncTcpConnection("$scheme://host:port"); Try / catch
try { $conn = new AsyncTcpConnection($address); } catch (RuntimeException $e) { if (str_contains($e->getMessage(), 'not exist')) { /* log config error, skip endpoint */ } throw $e; } Prevention
- Register the Protocols PSR-4 mapping in composer.json on day one and run composer dump-autoload after adding protocol classes
- Name protocol classes exactly as ucfirst of the scheme and match file casing on case-sensitive filesystems
- Run a startup smoke check that class_exists() for every configured scheme before serving traffic
When it happens
Trigger: new AsyncTcpConnection('myproto://host:80') without a Protocols\Myproto class; typo in a known protocol name, e.g. 'frame2://' or 'etxt://' instead of 'text://'; protocol class exists but the 'Protocols' namespace is not registered in composer's PSR-4 autoload; class filename casing does not match the ucfirst()-derived class name.
Common situations: New project where the custom protocol file was not created yet or sits in the wrong directory; composer.json missing the {"Protocols\\": "Protocols/"} PSR-4 mapping; forgot to run 'composer dump-autoload' after adding the mapping; on case-sensitive filesystems the file must be named exactly like the resolved class (e.g. Myproto.php).
Related errors
- class \Protocols\$scheme not exist
- Invalid protocol scheme '$scheme'
- Invalid protocol scheme '$scheme'
- Bad remoteAddress
- Request->session() fail, header already send
AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21).
Data as JSON: /api/errors/8f14b90dae324614.
Report an issue: GitHub.