walkor/workerman · error · RuntimeException
class \Protocols\$scheme not exist
Error message
class \Protocols\$scheme not exist
What it means
When the socketName scheme is not builtin, parseSocketAddress() ucfirst's it and tries class_exists() on two candidates: 'Protocols\Scheme' then 'Workerman\Protocols\Scheme'. If neither is autoloadable it throws this exception — i.e. you asked for an application-layer protocol but provided no class implementing it. The class must define the static protocol interface (input/decode/encode) Workerman calls on every buffer.
Source
Thrown at src/Worker.php:2569
protected function parseSocketAddress(): ?string
{
if (!$this->socketName) {
return null;
}
// 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
*/View on GitHub (pinned to 1391112a61)
Solutions
- Check the scheme spelling against the builtins first — http, ws, wss, text, frame, xmlrpc map to Workerman\Protocols classes; tcp/udp/unix/ssl are transports — a typo here is the most common cause.
- For a custom protocol, create Protocols/MyProto.php with `namespace Protocols;` and a StudlyCase class matching the scheme, defining static input(), decode() and encode().
- Make sure the class is autoloadable: add a psr-4 entry {"Protocols\\": "Protocols/"} to composer.json and run `composer dump-autoload`, or require the file manually before Worker::runAll().
- If the class lives in Workerman\Protocols, match the scheme to that exact class name (first letter upper-case after ucfirst).
Example fix
// before: no Protocols\Ftp class exists
$worker = new Worker('ftp://0.0.0.0:2121');
Worker::runAll(); // RuntimeException: class \Protocols\Ftp not exist
// after: implement the protocol class
// Protocols/Ftp.php
namespace Protocols;
class Ftp
{
public static function input(string $buffer, $connection): int { /* return consumed bytes */ }
public static function decode(string $buffer, $connection) { /* return request */ }
public static function encode($data, $connection): string { /* return bytes to send */ }
} Defensive patterns
Strategy: validation
Validate before calling
$scheme = ucfirst('MyProto'); // derived from your listen address
if (!isset(Workerman\Worker::BUILD_IN_TRANSPORTS[strtolower($scheme)])
&& !class_exists("Protocols\\$scheme")
&& !class_exists("Workerman\\Protocols\\$scheme")) {
throw new RuntimeException("Define Protocols\\$scheme before starting");
}
$worker = new Worker("$scheme://0.0.0.0:8080"); Type guard
function protocolClassExists(string $scheme): bool
{
$s = ucfirst($scheme);
return isset(Workerman\Worker::BUILD_IN_TRANSPORTS[strtolower($scheme)])
|| class_exists("Protocols\\$s")
|| class_exists("Workerman\\Protocols\\$s");
} Try / catch
try {
Worker::runAll();
} catch (RuntimeException $e) {
if (preg_match('/class \\Protocols\\(\w+) not exist/', $e->getMessage(), $m)) {
fwrite(STDERR, "Protocol class {$m[1]} missing — check autoload mapping for the Protocols namespace.\n");
exit(1);
}
throw $e;
} Prevention
- Add {"Protocols\\": "Protocols/"} to composer.json autoload psr-4 and run dump-autoload once the directory exists.
- Keep file name, class name, and scheme identical in StudlyCase.
- Add a boot-time assert that class_exists() for every custom protocol used in your config.
When it happens
Trigger: new Worker('ftp://0.0.0.0:2121') with no Protocols\Ftp class; a typo like 'htp://' or 'wss2://'; putting a custom protocol file in ./Protocols/MyProto.php that is not autoloadable (missing composer psr-4 mapping for the Protocols namespace, wrong file name vs class name, wrong namespace, or running from a different working directory).
Common situations: Following the custom-protocol docs but forgetting composer.json's autoload mapping for the Protocols namespace (or forgetting dump-autoload); naming the file myProto.php while the class is MyProto; declaring namespace App\Protocols instead of Protocols; misspelling a builtin scheme so it falls into the custom path.
Related errors
- Bad remoteAddress
- Invalid protocol scheme '$scheme'
- class \Protocols\$scheme not exist
- Invalid protocol scheme '$scheme'
- class \Protocols\$scheme not exist
AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21).
Data as JSON: /api/errors/5f2997a09ce6730d.
Report an issue: GitHub.