{"record":{"id":"62b29581ce9e0d1d","repo":"walkor/workerman","slug":"invalid-protocol-scheme-scheme","errorCode":null,"errorMessage":"Invalid protocol scheme '$scheme'","messagePattern":"Invalid protocol scheme '\\$scheme'","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Connection/AsyncTcpConnection.php","lineNumber":215,"sourceCode":"            }\n            $this->remoteHost = $addressInfo['host'];\n            $this->remotePort = $addressInfo['port'];\n            $this->remoteURI = \"{$addressInfo['path']}{$addressInfo['query']}\";\n            $scheme = $addressInfo['scheme'] ?? 'tcp';\n            $this->remoteAddress = 'unix' === strtolower($scheme)\n                ? substr($remoteAddress, strpos($remoteAddress, '/') + 2)\n                : $this->remoteHost . ':' . $this->remotePort;\n        }\n\n        $this->id = $this->realId = self::$idRecorder++;\n        if (PHP_INT_MAX === self::$idRecorder) {\n            self::$idRecorder = 0;\n        }\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        } else {\n            $this->transport = self::BUILD_IN_TRANSPORTS[$scheme];\n        }\n\n        // For statistics.\n        ++self::$statistics['connection_count'];\n        $this->maxSendBufferSize = self::$defaultMaxSendBufferSize;\n        $this->maxPackageSize = self::$defaultMaxPackageSize;\n        $this->socketContext = $socketContext;","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/walkor/workerman/blob/1391112a61d23020e11e7b89f17050f6cfaea431/src/Connection/AsyncTcpConnection.php#L197-L233","documentation":"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).","triggerScenarios":"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.","commonSituations":"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 ':'.","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"],"exampleFix":"// before\n$conn = new AsyncTcpConnection('my-proto://127.0.0.1:9000'); // throws Invalid protocol scheme 'my-proto'\n\n// after\n$conn = new AsyncTcpConnection('myproto://127.0.0.1:9000'); // resolves Protocols\\Myproto","handlingStrategy":"validation","validationCode":"$scheme = strtolower(explode('://', (string)$address, 2)[0] ?? '');\nif (!preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $scheme)) {\n    throw new InvalidArgumentException(\"Bad protocol scheme in address: $address\");\n}\n$conn = new AsyncTcpConnection($address);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["php","workerman","protocol","scheme-validation"],"backgroundTag":"invalid-url-scheme","analyzedSha":"1391112a61d23020e11e7b89f17050f6cfaea431","analyzedAt":"2026-08-21T02:05:46.744Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}