{"record":{"id":"187a5c240c4d6e93","repo":"matryer/xbar","slug":"unsupported-action-q","errorCode":null,"errorMessage":"unsupported action %q","messagePattern":"unsupported action %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/incoming_urls.go","lineNumber":34,"sourceCode":"\n// parseIncomingURL parses an incoming xbar:// URL.\nfunc parseIncomingURL(urlStr string) (incomingURL, error) {\n\tvar inURL incomingURL\n\tu, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn inURL, err\n\t}\n\tif u.Scheme != \"xbar\" && u.Host != \"app.xbarapp.com\" {\n\t\treturn inURL, errors.New(\"not an xbar:// url\")\n\t}\n\tinURL.Action = strings.Trim(u.Path, \"/\")\n\tinURL.Params = u.Query()\n\tswitch inURL.Action {\n\tcase \"openPlugin\":\n\tcase \"refreshPlugin\":\n\tcase \"refreshAllPlugins\":\n\tdefault: // not ok\n\t\treturn inURL, errors.Errorf(\"unsupported action %q\", inURL.Action)\n\t}\n\treturn inURL, nil\n}\n","sourceCodeStart":16,"sourceCodeEnd":38,"githubUrl":"https://github.com/matryer/xbar/blob/d624239058997c80118eaebe2e7f8331b3c765e0/app/incoming_urls.go#L16-L38","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","solutions":["Use one of the supported actions exactly: openPlugin, refreshPlugin, refreshAllPlugins","Include a non-empty path in the URL, e.g. xbar://refreshPlugin?path=/users/me/cpu.5s.sh","Match the case exactly — actions are lowercase","Check the app version supports the action you're linking to and update the link or app"],"exampleFix":"// before\nparseIncomingURL(\"xbar://refresh-plugins?path=/cpu.5s.sh\")\n// after\nparseIncomingURL(\"xbar://refreshPlugin?path=/cpu.5s.sh\")","handlingStrategy":"validation","validationCode":"var validActions = map[string]bool{\"openPlugin\": true, \"refreshPlugin\": true, \"refreshAllPlugins\": true}\n\nfunc hasKnownAction(raw string) bool {\n\tu, err := url.Parse(raw)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn validActions[strings.Trim(u.Path, \"/\")]\n}","typeGuard":"func isSupportedAction(action string) bool {\n\treturn action == \"openPlugin\" || action == \"refreshPlugin\" || action == \"refreshAllPlugins\"\n}","tryCatchPattern":"inURL, err := parseIncomingURL(raw)\nif err != nil {\n\tvar unsupported string\n\tif _, scan := fmt.Sscanf(err.Error(), \"unsupported action %q\", &unsupported); scan == nil {\n\t\tlog.Printf(\"unknown deep-link action %q, ignoring\", unsupported)\n\t\treturn\n\t}\n\treturn err\n}","preventionTips":["Centralize deep-link construction in one helper that only emits the three known actions","Keep action names lowercase and exact","Never build links from untrusted path input without whitelisting the action","Add a table-driven test enumerating all supported actions"],"tags":["url","parsing","unsupported-action","go"],"backgroundTag":"unsupported-url-action","analyzedSha":"d624239058997c80118eaebe2e7f8331b3c765e0","analyzedAt":"2026-09-02T22:38:22.007Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}