walkor/workerman · error · RuntimeException
class \Protocols\$scheme not exist
Error message
class \Protocols\$scheme not exist
What it means
For AsyncUdpConnection, any scheme other than 'udp' is resolved as an application-layer protocol class: '\Protocols\<Scheme>' first, then '\Workerman\Protocols\<Scheme>'. When neither class can be autoloaded the constructor throws. This mirrors the TCP connection behavior and is how custom UDP wire formats are plugged in.
Source
Thrown at src/Connection/AsyncUdpConnection.php:92
* @param string $remoteAddress
* @throws Throwable
*/
public function __construct($remoteAddress, $contextOption = [])
{
// Get the application layer communication protocol and listening address.
[$scheme, $address] = explode(':', $remoteAddress, 2);
// Check application layer protocol class.
if ($scheme !== 'udp') {
// 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");
}
}
}
$this->remoteAddress = substr($address, 2);
$this->contextOption = $contextOption;
}
/**
* For udp package.
*
* @param resource $socket
* @return void
*/
public function baseRead($socket): void
{
$recvBuffer = stream_socket_recvfrom($socket, static::MAX_UDP_PACKAGE_SIZE, 0, $remoteAddress);
if (false === $recvBuffer || empty($remoteAddress)) {View on GitHub (pinned to 1391112a61)
Solutions
- Create Protocols/Mydns.php with namespace Protocols, class Mydns, implementing input/decode/encode static methods
- Register the namespace in composer.json ("psr-4": {"Protocols\\": "Protocols/"}) and run composer dump-autoload
- Or switch to plain 'udp://host:port' if no application protocol layer is needed
Example fix
// before
$conn = new AsyncUdpConnection('mydns://8.8.8.8:53'); // throws class \Protocols\Mydns not exist
// after
// Protocols/Mydns.php
class Mydns { /* protocol implementation */ }
// with PSR-4 mapping for Protocols\\ and composer dump-autoload run
$conn = new AsyncUdpConnection('mydns://8.8.8.8:53'); Defensive patterns
Strategy: validation
Validate before calling
$scheme = 'mydns';
if ($scheme !== 'udp'
&& !class_exists('\\Protocols\\' . ucfirst($scheme))
&& !class_exists('\\Workerman\\Protocols\\' . ucfirst($scheme))) {
throw new InvalidArgumentException("Define Protocols\\" . ucfirst($scheme) . ' before using ' . "$scheme://");
}
$conn = new AsyncUdpConnection("$scheme://8.8.8.8:53"); Prevention
- Create the protocol class before writing the connection code, and verify it autoloads with a tiny php -r class_exists check
- Keep the Protocols PSR-4 mapping in composer.json current
When it happens
Trigger: new AsyncUdpConnection('mydns://host:53') without defining Protocols\Mydns; typo such as 'dns2://' instead of the intended protocol name; protocol file present but the Protocols namespace is not in composer's PSR-4 autoload map; case mismatch between file name and the ucfirst()-derived class name on Linux.
Common situations: Prototyping a DNS-like or game UDP protocol and forgetting the protocol class; moving code into a project whose composer.json lacks the Protocols PSR-4 mapping; forgetting 'composer dump-autoload' after adding the mapping.
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/7c07fe24d5754e72.
Report an issue: GitHub.