{"record":{"id":"67c36a1600a78d5e","repo":"chenhg5/cc-connect","slug":"xdg-open-not-found-headless-server-w","errorCode":null,"errorMessage":"xdg-open not found (headless server?): %w","messagePattern":"xdg-open not found \\(headless server\\?\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/cc-connect/web.go","lineNumber":92,"sourceCode":"\t\tfmt.Printf(\"\\nCould not open browser automatically.\\n\")\n\t\tfmt.Printf(\"Open this URL in your browser:\\n\")\n\t\tfmt.Printf(\"  %s/login?token=%s\\n\", baseURL, token)\n\t\tfmt.Printf(\"\\nNote: make sure cc-connect is running (it hosts the web admin on port %d).\\n\", port)\n\t}\n}\n\nfunc openBrowser(rawURL string) error {\n\tswitch runtime.GOOS {\n\tcase \"darwin\":\n\t\treturn exec.Command(\"open\", rawURL).Start()\n\tcase \"linux\":\n\t\tif isWSL() {\n\t\t\treturn exec.Command(\"cmd.exe\", \"/c\", \"start\", rawURL).Start()\n\t\t}\n\t\t// On headless Linux, xdg-open is often unavailable.\n\t\t// Check early and return a clear error so the caller can print the URL.\n\t\tif _, err := exec.LookPath(\"xdg-open\"); err != nil {\n\t\t\treturn fmt.Errorf(\"xdg-open not found (headless server?): %w\", err)\n\t\t}\n\t\treturn exec.Command(\"xdg-open\", rawURL).Start()\n\tcase \"windows\":\n\t\treturn exec.Command(\"cmd\", \"/c\", \"start\", rawURL).Start()\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported OS: %s\", runtime.GOOS)\n\t}\n}\n\nfunc isWSL() bool {\n\tdata, err := os.ReadFile(\"/proc/version\")\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn strings.Contains(strings.ToLower(string(data)), \"microsoft\")\n}\n","sourceCodeStart":74,"sourceCodeEnd":109,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/web.go#L74-L109","documentation":"openBrowser, used by `cc-connect web` (runWeb), opens the dashboard URL in a browser. On Linux it first looks up xdg-open via exec.LookPath; when missing it returns \"xdg-open not found (headless server?)\" instead of silently failing to start a browser. The web server itself still runs — the caller is expected to print the URL so the user can open it remotely.","triggerScenarios":"Running `cc-connect web` (which calls openBrowser) on a Linux machine without xdg-open in PATH — typically headless servers, containers, SSH sessions without a desktop environment, or minimal distro images lacking xdg-utils.","commonSituations":"Starting the web dashboard on a VPS or Docker container; SSH-ing into a CI box; a slim Debian/Alpine image without the xdg-utils package.","solutions":["Open the printed URL manually in your local browser — the web server is running regardless.","Install xdg-utils (apt install xdg-utils / dnf install xdg-utils) if the machine actually has a desktop.","Set $BROWSER to a usable browser or script so the opener has a target.","If connecting remotely, use SSH port forwarding: ssh -L 8080:localhost:8080 user@host, then browse http://localhost:8080.","On WSL, verify /proc/version is readable so isWSL() can route to cmd.exe /c start instead of xdg-open."],"exampleFix":"// before\ncc-connect web   # on headless server: xdg-open not found\n// after\ncc-connect web\n# copy the printed URL, or: ssh -L 8080:localhost:8080 user@server","handlingStrategy":"fallback","validationCode":"if _, err := exec.LookPath(\"xdg-open\"); err != nil {\n    fmt.Println(\"No browser available; open the URL manually:\", url)\n}","typeGuard":null,"tryCatchPattern":"if err := openBrowser(url); err != nil {\n    var notFoundErr *exec.Error\n    if errors.As(err, &notFoundErr) || strings.Contains(err.Error(), \"xdg-open not found\") {\n        fmt.Println(\"Web UI running at:\", url) // print URL instead of failing\n    }\n}","preventionTips":["Install xdg-utils on desktop Linux machines","Set $BROWSER in headless/CI environments","Expect the URL to be printed on headless servers and open it locally","Use SSH port forwarding for remote dashboards"],"tags":["browser","headless","linux"],"backgroundTag":"command-not-found","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}