matryer/xbar · error

unsupported action

Error message

unsupported action %q

What it means

After the scheme check, parseIncomingURL extracts the action from the URL path and dispatches only on the three known actions: openPlugin, refreshPlugin, refreshAllPlugins. Anything else (empty path, typo, new/renamed action) falls to the default branch and is rejected with the offending action quoted, preventing arbitrary path traversal through the handler.

Solutions

  1. Use one of the supported actions exactly: openPlugin, refreshPlugin, refreshAllPlugins
  2. Include a non-empty path in the URL, e.g. xbar://refreshPlugin?path=/users/me/cpu.5s.sh
  3. Match the case exactly — actions are lowercase
  4. Check the app version supports the action you're linking to and update the link or app

Example fix

// before
parseIncomingURL("xbar://refresh-plugins?path=/cpu.5s.sh")
// after
parseIncomingURL("xbar://refreshPlugin?path=/cpu.5s.sh")
Defensive patterns

Strategy: validation

Validate before calling

var validActions = map[string]bool{"openPlugin": true, "refreshPlugin": true, "refreshAllPlugins": true}

func hasKnownAction(raw string) bool {
	u, err := url.Parse(raw)
	if err != nil {
		return false
	}
	return validActions[strings.Trim(u.Path, "/")]
}

Type guard

func isSupportedAction(action string) bool {
	return action == "openPlugin" || action == "refreshPlugin" || action == "refreshAllPlugins"
}

Try / catch

inURL, err := parseIncomingURL(raw)
if err != nil {
	var unsupported string
	if _, scan := fmt.Sscanf(err.Error(), "unsupported action %q", &unsupported); scan == nil {
		log.Printf("unknown deep-link action %q, ignoring", unsupported)
		return
	}
	return err
}

Prevention

When it happens

Trigger: parseIncomingURL called with a valid xbar:// URL whose trimmed path is not one of the three supported actions, e.g. xbar://openPlugins (typo), xbar:// (empty path), or xbar://installPlugin?path=... (unsupported action).

Common situations: Typos in action names when constructing deep links programmatically; forgetting the path entirely (xbar://?path=...); copying an action name from a newer or older app version where the action set differs; case sensitivity mistakes (OpenPlugin).

Related errors


AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02). Data as JSON: /api/errors/187a5c240c4d6e93. Report an issue: GitHub.

Appendix: source

Thrown at app/incoming_urls.go:34

// parseIncomingURL parses an incoming xbar:// URL.
func parseIncomingURL(urlStr string) (incomingURL, error) {
	var inURL incomingURL
	u, err := url.Parse(urlStr)
	if err != nil {
		return inURL, err
	}
	if u.Scheme != "xbar" && u.Host != "app.xbarapp.com" {
		return inURL, errors.New("not an xbar:// url")
	}
	inURL.Action = strings.Trim(u.Path, "/")
	inURL.Params = u.Query()
	switch inURL.Action {
	case "openPlugin":
	case "refreshPlugin":
	case "refreshAllPlugins":
	default: // not ok
		return inURL, errors.Errorf("unsupported action %q", inURL.Action)
	}
	return inURL, nil
}

View on GitHub (pinned to d624239058)