{"record":{"id":"0f2875d86e3de74f","repo":"walkor/workerman","slug":"invalid-protocol-scheme-scheme-0f2875","errorCode":null,"errorMessage":"Invalid protocol scheme '$scheme'","messagePattern":"Invalid protocol scheme '\\$scheme'","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Worker.php","lineNumber":2562,"sourceCode":"            }\n        }\n    }\n\n    /**\n     * Parse local socket address.\n     */\n    protected function parseSocketAddress(): ?string\n    {\n        if (!$this->socketName) {\n            return null;\n        }\n        // Get the application layer communication protocol and listening address.\n        [$scheme, $address] = explode(':', $this->socketName, 2);\n        // Check application layer protocol class.\n        if (!isset(self::BUILD_IN_TRANSPORTS[$scheme])) {\n            // Validate scheme contains only safe characters for class name resolution.\n            if (!preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $scheme)) {\n                throw new RuntimeException(\"Invalid protocol scheme '$scheme'\");\n            }\n            $scheme = ucfirst($scheme);\n            $this->protocol = 'Protocols\\\\' . $scheme;\n            if (!class_exists($this->protocol)) {\n                $this->protocol = \"Workerman\\\\Protocols\\\\$scheme\";\n                if (!class_exists($this->protocol)) {\n                    throw new RuntimeException(\"class \\\\Protocols\\\\$scheme not exist\");\n                }\n            }\n\n            if (!isset(self::BUILD_IN_TRANSPORTS[$this->transport])) {\n                throw new RuntimeException('Bad worker->transport ' . var_export($this->transport, true));\n            }\n        } else if ($this->transport === 'tcp') {\n            $this->transport = $scheme;\n        }\n        //local socket\n        return self::BUILD_IN_TRANSPORTS[$this->transport] . \":\" . $address;","sourceCodeStart":2544,"sourceCodeEnd":2580,"githubUrl":"https://github.com/walkor/workerman/blob/1391112a61d23020e11e7b89f17050f6cfaea431/src/Worker.php#L2544-L2580","documentation":"parseSocketAddress() splits the Worker's $socketName on the first ':' and treats the part before it as a protocol scheme. If the scheme is not one of the built-in transports (tcp, udp, unix, ssl), Workerman maps it to a PHP class name (Protocols\\Scheme). Before doing that it validates the scheme against ^[a-zA-Z][a-zA-Z0-9]*$ and throws 'Invalid protocol scheme' when it contains characters that are illegal in a class name. This exists both as a config sanity check and so arbitrary strings cannot reach class resolution.","triggerScenarios":"Constructing a Worker whose listen address has a non-builtin scheme containing hyphens, dots, underscores, a leading digit, or non-ASCII characters, e.g. new Worker('my-text-protocol://0.0.0.0:8080'), new Worker('foo.bar://...'), new Worker('2fast://...'), or a mistyped scheme like 'http -' or an empty scheme (':8080').","commonSituations":"Naming a custom protocol class with kebab-case (My-Text-Protocol) instead of StudlyCase; copying a protocol name from a URL/queue config that uses '+' or '-' separators (ws+tls, ssl-ws); a typo or stray character before the colon in $worker->listen.","solutions":["Fix the scheme to be a letter-first alphanumeric word that matches your protocol class name, e.g. 'MyTextProtocol://0.0.0.0:8080' for class Protocols\\MyTextProtocol.","If you meant a standard protocol, use the builtin scheme spelling instead: http, https, ws, wss (these resolve to Workerman\\Protocols\\Http/Http2? no — Http, Ws classes) or transports tcp/udp/unix/ssl.","Rename the protocol class/file to StudlyCase alphanumerics (e.g. Protocols/MyTextProtocol.php) so scheme and class name line up."],"exampleFix":"// before: hyphenated scheme cannot map to a PHP class name\n$worker = new Worker('my-text-protocol://0.0.0.0:8080');\n\n// after: letter-first alphanumeric scheme matching Protocols\\MyTextProtocol\n$worker = new Worker('MyTextProtocol://0.0.0.0:8080');","handlingStrategy":"validation","validationCode":"$socketName = 'MyProto://0.0.0.0:8080';\n$scheme = strtok($socketName, ':') ?: '';\nif (!preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $scheme)) {\n    throw new InvalidArgumentException(\"Bad protocol scheme '$scheme' (must be letter-first alphanumeric)\");\n}\n$worker = new Worker($socketName);","typeGuard":"function isValidWorkermanScheme(string $socketName): bool\n{\n    $scheme = strtok($socketName, ':') ?: '';\n    $builtin = ['tcp', 'udp', 'unix', 'ssl', 'http', 'https', 'ws', 'wss', 'text', 'frame'];\n    return in_array(strtolower($scheme), $builtin, true)\n        || (bool) preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $scheme);\n}","tryCatchPattern":null,"preventionTips":["Name custom protocols in StudlyCase alphanumerics only (MyTextProtocol, not my-text-protocol).","Centralize listen addresses in one config file and lint the scheme format in tests."],"tags":["workerman","protocol-scheme","config-validation","socket-name","php"],"backgroundTag":"invalid-url-scheme","analyzedSha":"1391112a61d23020e11e7b89f17050f6cfaea431","analyzedAt":"2026-08-21T02:05:46.744Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}