{"record":{"id":"782b991bddf5f3e2","repo":"flarum/framework","slug":"paths-are-not-possible-in-websocket-connections","errorCode":null,"errorMessage":"Paths are not possible in websocket connections.","messagePattern":"Paths are not possible in websocket connections\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/realtime/src/Extend/Realtime.php","lineNumber":103,"sourceCode":"    // -------------------------------------------------------------------------\n    // Server configuration\n    // -------------------------------------------------------------------------\n\n    /**\n     * Provide the full url to the running `php flarum realtime:serve` daemon.\n     * In case you proxy it, use the outside URL.\n     *\n     * @example https://wss.flarum.site\n     * @example https://flarum.site:9001\n     *\n     * @see `php flarum realtime:serve --help`\n     */\n    public function daemonUrl(string $url): self\n    {\n        $parsed = parse_url($url);\n\n        if (! empty($parsed['path'])) {\n            throw new InvalidArgumentException('Paths are not possible in websocket connections.');\n        }\n\n        $this->configuration['php-client-secure'] = ($parsed['scheme'] ?? 'http') === 'https';\n        $this->configuration['php-client-host'] = $parsed['host'] ?? '';\n        $this->configuration['php-client-port'] = $parsed['port'] ?? null;\n\n        $this->configuration['js-client-secure'] = ($parsed['scheme'] ?? 'http') === 'https';\n        $this->configuration['js-client-host'] = $parsed['host'] ?? '';\n        $this->configuration['js-client-port'] = $parsed['port'] ?? null;\n\n        return $this;\n    }\n\n    /**\n     * Set maximum number of allowed websocket connections.\n     */\n    public function maxConnections(int $connections): self\n    {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/extensions/realtime/src/Extend/Realtime.php#L85-L121","documentation":"The realtime extension's daemonUrl() parses the daemon websocket URL and rejects URLs containing a path component, since websocket connections to the daemon go to host:port only; it throws InvalidArgumentException otherwise.","triggerScenarios":"Configuring the realtime daemon URL with a path suffix, e.g. http://host:8080/socket or wss://example.com/realtime, when calling Extend\\Realtime::daemonUrl() in the extension bootstrap.","commonSituations":"Copy-pasting a full app URL including a base path; assuming the daemon needs a route prefix; reverse-proxy setups where the public URL includes a path.","solutions":["Remove the path from the configured URL, keeping scheme://host:port (e.g. wss://realtime.example.com).","If a path is needed for proxies, handle path routing at the proxy level, not in the daemon URL config.","Verify with parse_url semantics: anything after host/port (leading '/') is rejected."],"exampleFix":"// before\n(new Extend\\Realtime())->daemonUrl('https://example.com/realtime')\n// after\n(new Extend\\Realtime())->daemonUrl('https://realtime.example.com:8080')","handlingStrategy":"validation","validationCode":"$parsed = parse_url($url); if (! empty($parsed['path'])) { throw new InvalidArgumentException('daemon URL must not contain a path'); }","typeGuard":null,"tryCatchPattern":"try { $ext->daemonUrl($url); } catch (InvalidArgumentException $e) { /* strip path and retry */ }","preventionTips":["Configure only scheme://host:port for the realtime daemon","Handle path routing at the reverse proxy, not in the URL","Add a config linter that rejects URLs with path components"],"tags":["configuration","websocket","url"],"backgroundTag":"invalid-url","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}