{"record":{"id":"5f2997a09ce6730d","repo":"walkor/workerman","slug":"class-protocols-scheme-not-exist-5f2997","errorCode":null,"errorMessage":"class \\Protocols\\$scheme not exist","messagePattern":"class \\\\Protocols\\\\\\$scheme not exist","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Worker.php","lineNumber":2569,"sourceCode":"    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;\n    }\n\n    /**\n     * Pause accept new connections.\n     *\n     * @return void\n     */","sourceCodeStart":2551,"sourceCodeEnd":2587,"githubUrl":"https://github.com/walkor/workerman/blob/1391112a61d23020e11e7b89f17050f6cfaea431/src/Worker.php#L2551-L2587","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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)."],"exampleFix":"// before: no Protocols\\Ftp class exists\n$worker = new Worker('ftp://0.0.0.0:2121');\nWorker::runAll(); // RuntimeException: class \\Protocols\\Ftp not exist\n\n// after: implement the protocol class\n// Protocols/Ftp.php\nnamespace Protocols;\nclass Ftp\n{\n    public static function input(string $buffer, $connection): int { /* return consumed bytes */ }\n    public static function decode(string $buffer, $connection) { /* return request */ }\n    public static function encode($data, $connection): string { /* return bytes to send */ }\n}","handlingStrategy":"validation","validationCode":"$scheme = ucfirst('MyProto'); // derived from your listen address\nif (!isset(Workerman\\Worker::BUILD_IN_TRANSPORTS[strtolower($scheme)])\n    && !class_exists(\"Protocols\\\\$scheme\")\n    && !class_exists(\"Workerman\\\\Protocols\\\\$scheme\")) {\n    throw new RuntimeException(\"Define Protocols\\\\$scheme before starting\");\n}\n$worker = new Worker(\"$scheme://0.0.0.0:8080\");","typeGuard":"function protocolClassExists(string $scheme): bool\n{\n    $s = ucfirst($scheme);\n    return isset(Workerman\\Worker::BUILD_IN_TRANSPORTS[strtolower($scheme)])\n        || class_exists(\"Protocols\\\\$s\")\n        || class_exists(\"Workerman\\\\Protocols\\\\$s\");\n}","tryCatchPattern":"try {\n    Worker::runAll();\n} catch (RuntimeException $e) {\n    if (preg_match('/class \\\\Protocols\\\\(\\w+) not exist/', $e->getMessage(), $m)) {\n        fwrite(STDERR, \"Protocol class {$m[1]} missing — check autoload mapping for the Protocols namespace.\\n\");\n        exit(1);\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["workerman","protocol-class","class-not-found","autoload","php"],"backgroundTag":"protocol-class-not-found","analyzedSha":"1391112a61d23020e11e7b89f17050f6cfaea431","analyzedAt":"2026-08-21T02:05:46.744Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}