walkor/workerman · error · RuntimeException
Invalid protocol scheme '$scheme'
Error message
Invalid protocol scheme '$scheme'
What it means
When the scheme is not one of the built-in transports (tcp, udp, unix, ssl, sslv2, sslv3, tls), Workerman treats it as an application-layer protocol class name and must build a PHP class name from it. Before resolving '\Protocols\<Scheme>' it validates the scheme against /^[a-zA-Z][a-zA-Z0-9]*$/ and throws when the scheme contains characters unsafe for class-name resolution (hyphens, dots, digits-first, symbols).
Source
Thrown at src/Connection/AsyncTcpConnection.php:215
}
$this->remoteHost = $addressInfo['host'];
$this->remotePort = $addressInfo['port'];
$this->remoteURI = "{$addressInfo['path']}{$addressInfo['query']}";
$scheme = $addressInfo['scheme'] ?? 'tcp';
$this->remoteAddress = 'unix' === strtolower($scheme)
? substr($remoteAddress, strpos($remoteAddress, '/') + 2)
: $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;View on GitHub (pinned to 1391112a61)
Solutions
- Rename the custom protocol scheme to letters/digits only starting with a letter, e.g. 'myproto://host:1234', and name the class Protocols\Myproto
- Use a built-in transport scheme (tcp, udp, unix, ssl, tls) when no custom application protocol is needed
- Fix the address typo so the scheme section is a clean identifier
Example fix
// before
$conn = new AsyncTcpConnection('my-proto://127.0.0.1:9000'); // throws Invalid protocol scheme 'my-proto'
// after
$conn = new AsyncTcpConnection('myproto://127.0.0.1:9000'); // resolves Protocols\Myproto Defensive patterns
Strategy: validation
Validate before calling
$scheme = strtolower(explode('://', (string)$address, 2)[0] ?? '');
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $scheme)) {
throw new InvalidArgumentException("Bad protocol scheme in address: $address");
}
$conn = new AsyncTcpConnection($address); Prevention
- Keep custom protocol schemes alphanumeric and letter-first by convention (myproto, not my-proto)
- Keep the list of allowed schemes in one config constant and validate against it at boot
When it happens
Trigger: new AsyncTcpConnection('my-proto://host:1234') (hyphen in scheme), a scheme starting with a digit such as '2fa://host', a scheme with a dot or slash like 'app.v2://host', or a malformed raw address whose text before the first ':' contains junk after parse_url() failed.
Common situations: Teams naming custom protocols with dashes (my-protocol://) instead of alphanumeric PascalCase; copy-pasting a URL with credentials or a subdomain-like scheme; typos like 'tcp-ssl://'; addresses built by string concatenation that leave stray characters before ':'.
Related errors
- Invalid protocol scheme '$scheme'
- class \Protocols\$scheme not exist
- class \Protocols\$scheme not exist
- Bad remoteAddress
- Request->session() fail, header already send
AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21).
Data as JSON: /api/errors/62b29581ce9e0d1d.
Report an issue: GitHub.