opentofu/opentofu · warning

%s: %w

Error message

%s: %w

What it means

Returned by the exec-based browser launcher when the program named in the BROWSER environment variable exits non-zero or cannot be run. The launcher (used by 'tofu login' to open the browser for device/OAuth flows) builds an exec.Cmd with the BROWSER value as the executable and the URL as its only argument, and wraps any cmd.Run() failure as "<execPath>: <cause>".

Source

Thrown at internal/command/webbrowser/exec.go:45

func NewExecLauncher(execPath string) Launcher {
	return execLauncher{
		execPath: execPath,
	}
}

type execLauncher struct {
	execPath string
}

func (l execLauncher) OpenURL(url string) error {
	cmd := &exec.Cmd{
		Path: l.execPath,
		Args: []string{l.execPath, url},
		Env:  os.Environ(),
	}
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("%s: %w", l.execPath, err)
	}
	return nil
}

// ParseBrowserEnv takes the raw value of a BROWSER environment variable and
// attempts to parse it as a reference to an executable, whose absolute
// path is returned if successful. Returns an empty string if the value cannot
// be interpreted as an executable to run.
//
// This implements the simple form of this environment variable commonly used
// by software on Unix-like systems, where the value must be literally just
// a command to run whose first and only argument would be the URL to open.
//
// It does NOT support the more complex interpretation of that environment
// variable that was proposed at http://www.catb.org/~esr/BROWSER/ , because
// that form has not been widely implemented and the implementations that
// exist do not have consistent behavior due to the proposal being
// ambiguous.

View on GitHub (pinned to 3561785c48)

Solutions

  1. Unset BROWSER (or set it to a real, working browser command) and re-run 'tofu login'
  2. If the auto-open fails, copy the printed URL and open it manually on any machine, then paste the code back - the login flow supports this
  3. On headless machines use BROWSER=echo or similar so the URL is just printed
  4. Verify the browser binary exists and is executable: which $BROWSER

Example fix

# before
BROWSER=firefox tofu login   # fails: firefox: exec format error / not found
# after
BROWSER=echo tofu login      # prints URL to terminal for manual opening
# or: unset BROWSER; tofu login
Defensive patterns

Strategy: fallback

Validate before calling

# Before 'tofu login', confirm BROWSER is executable if set
if [ -n "$BROWSER" ] && ! command -v "${BROWSER%% *}" >/dev/null 2>&1; then
  echo "BROWSER=$BROWSER is not runnable; falling back to manual URL" >&2
  BROWSER=echo tofu login
else
  tofu login
fi

Type guard

func browserLaunchErr(err error) bool {
  // exec.go wraps as "<execPath>: %w" - match on ': exec:' or exit-error shapes
  return err != nil && (strings.Contains(err.Error(), ": exec:") || strings.Contains(err.Error(), "exit status"))
}

Try / catch

err := browser.OpenURL(url)
if err != nil {
  // non-fatal by design: show the URL and continue the login flow manually
  fmt.Printf("Could not open browser automatically (%v)\nVisit this URL: %s\n", err, url)
}

Prevention

When it happens

Trigger: 'tofu login' (or anything calling webbrowser.OpenURL) with BROWSER set to a command that fails to launch: binary not found ($PATH lookup failure), not executable, or the browser process returns a non-zero exit status (common on headless systems with browsers like w3m that fail without a display).

Common situations: SSH sessions or containers where BROWSER is set to something that needs a GUI; stale BROWSER value pointing at a removed browser; CI environments where 'tofu login' is attempted non-interactively.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/46743baff8bda74d. Report an issue: GitHub.