Skip to content

Fix browser opening on WSL2 with centralized browser package#91

Open
rodmhgl wants to merge 5 commits intoiximiuz:mainfrom
rodmhgl:fix/wsl2-browser-support
Open

Fix browser opening on WSL2 with centralized browser package#91
rodmhgl wants to merge 5 commits intoiximiuz:mainfrom
rodmhgl:fix/wsl2-browser-support

Conversation

@rodmhgl
Copy link

@rodmhgl rodmhgl commented Feb 28, 2026

Summary

  • Add internal/browser/ package that detects WSL (via /proc/version) and uses wslviewcmd.exe /c startxdg-open fallback chain to open the Windows browser
  • Replace the duplicated open.Run + fallback pattern across all 9 call sites with browser.OpenWithFallbackMessage()
  • Improve fallback UX by displaying the URL prominently on its own line when the browser can't be opened
  • Fix pre-existing go vet warnings for non-constant format strings in NewStatusError calls

Resolves #90

Motivation

On WSL2, xdg-open (used by open-golang) fails to open the Windows browser. This breaks the UX for labctl auth login and all other commands that open URLs the user sees a generic "Couldn't open the browser" message with no easy way to copy the URL. On manually copying the URL to login through the browser in Windows, the callback never makes it back to the CLI in WSL2 and hangs.

This also unblocks the other workflows that open URLs (such as challenge start) on WSL2.

Before:

  Opening https://labs.iximiuz.com/auth/sessions/69a221... in your browser...
          ^C

After:

Browser flow successful

  Opening https://labs.iximiuz.com/auth/sessions/69a221... in your browser...

  Waiting for the session to be authorized... Done.

  Session authorized. You can now use labctl commands.

Unable to open browser

  Opening https://labs.iximiuz.com/auth/sessions/69a221... in your browser...

  Could not open browser automatically.
  Please open this URL in your browser:

    https://labs.iximiuz.com/auth/sessions/69a221...

Test plan

  • go build ./... compiles cleanly
  • go test ./... all tests pass (including new internal/browser/ tests)
  • go vet ./... no warnings
  • Manual: labctl auth login on WSL2 opens Windows browser and completes login
  • Manual: if browser open fails, URL is prominently displayed and easy to copy
  • Manual: labctl auth login in Mac OS opens browser and completes login

Pass explicit "%s" format specifier in NewStatusError calls where
err.Error() was used directly as the format string, which go vet
flags as unsafe if the error message contains printf verbs.
On WSL2, xdg-open fails to open the Windows browser, breaking the
auth login flow and all other URL-opening commands. This adds a
centralized browser package that detects WSL via /proc/version and
tries wslview, cmd.exe, then xdg-open as fallbacks. The fallback
message now prominently displays the URL on its own line for easy
copying.

Replaces duplicated open.Run + fallback pattern across 9 call sites.
Copilot AI review requested due to automatic review settings February 28, 2026 00:17
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes and improves URL browser-opening behavior (especially on WSL2) by introducing a dedicated internal/browser package and updating all CLI call sites to use a consistent open+fallback UX.

Changes:

  • Add internal/browser with WSL detection and a WSL-specific opener chain (wslviewcmd.exe /c startopen-golang fallback).
  • Replace duplicated “open browser + fallback message” logic across commands with browser.OpenWithFallbackMessage.
  • Fix go vet warnings by switching NewStatusError call sites to use constant format strings.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/labcli/cliutil.go Fix go vet format-string warnings in WrapStatusError.
internal/browser/browser.go New browser-opening helper with WSL detection and unified fallback messaging.
internal/browser/browser_test.go Add unit tests for WSL detection and fallback message formatting.
cmd/auth/login.go Use centralized browser open + improved fallback UX for auth login.
cmd/challenge/start.go Use centralized browser open + fallback message.
cmd/content/create.go Use centralized browser open + fallback message after content creation.
cmd/course/start.go Use centralized browser open + fallback message for lesson start.
cmd/expose/port.go Use centralized browser open + fallback message for exposed ports.
cmd/expose/shell.go Use centralized browser open + fallback message for exposed shell sessions.
cmd/playground/restart.go Use centralized browser open + fallback message for restarts.
cmd/playground/start.go Use centralized browser open + fallback message for playground start.
cmd/playground/tasks.go Fix go vet format-string warning in NewStatusError.
cmd/tutorial/start.go Use centralized browser open + fallback message for tutorial start.
go.sum Dependency checksum updates due to module graph changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

tryExec previously used cmd.Start() which only checks if the process
launched, not if it succeeded. If wslview or cmd.exe started but exited
non-zero, Open() would return nil and the user would never see the
fallback URL message. Using cmd.Run() waits for exit and checks status,
ensuring the fallback chain works correctly.
URLs commonly contain & for query parameters, which cmd.exe interprets
as a command separator. Without quoting, 'start "" https://example.com?a=1&b=2'
would execute 'start "" https://example.com?a=1' and then 'b=2' as a
separate command. Wrapping the URL in double quotes prevents this.
Add a package-level openFunc variable that OpenWithFallbackMessage uses
instead of calling Open directly. Tests swap in a stub via stubOpen(),
enabling deterministic assertions for both the success path (no fallback
printed) and failure path (fallback URL displayed) without launching
any external processes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auth login flow freezes in WSL2

2 participants