{"record":{"id":"54cf683d4c2211c4","repo":"gitbutlerapp/gitbutler","slug":"errors-occurred-cmd-errors","errorCode":null,"errorMessage":"Errors occurred: {cmd_errors:?}","messagePattern":"Errors occurred: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/open/mod.rs","lineNumber":129,"sourceCode":"            \"LD_LIBRARY_PATH\",\n            \"PATH\",\n            \"PERLLIB\",\n            \"PYTHONHOME\",\n            \"PYTHONPATH\",\n            \"QT_PLUGIN_PATH\",\n            \"XDG_DATA_DIRS\",\n        ]);\n\n        cmd.envs(cleaned_vars);\n        cmd.current_dir(env::temp_dir());\n        if cmd.status().is_ok() {\n            return Ok(());\n        } else {\n            cmd_errors.push(anyhow::anyhow!(\"Failed to execute command {cmd:?}\"));\n        }\n    }\n    if !cmd_errors.is_empty() {\n        bail!(\"Errors occurred: {cmd_errors:?}\");\n    }\n    Ok(())\n}\n\n/// Opens supported editor URLs directly inside WSL.\n///\n/// The normal URL opener can fail to route `vscode://file/...`-style URLs back\n/// to Linux editor CLIs when GitButler runs in WSL, so this attempts a direct\n/// invocation first. Returns `true` only when a supported editor command was\n/// executed successfully; unsupported URLs and failed launches fall back to the\n/// generic opener.\nfn open_editor_url_as_command_invocation_on_wsl(target_url: &Url) -> bool {\n    use std::process::Command;\n\n    if !is_wsl() {\n        return false;\n    }\n","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/open/mod.rs#L111-L147","documentation":"After the scheme check, open_that (crates/but-api/src/open/mod.rs:98-131) runs every opener command the `open` crate derives for the platform and pushes a 'Failed to execute command' entry whenever cmd.status() itself errors (the process could not be spawned at all, distinct from a non-zero exit). If every candidate failed, the aggregated bail at line 129 fires listing all failed commands.","triggerScenarios":"Minimal or headless Linux where no xdg-open/gio/kde-open exists; a broken PATH inside the app environment (launched from a launcher rather than a shell); WSL without an opener where an unsupported editor URL fell back to the generic opener.","commonSituations":"GitButler packaged as an AppImage/sandboxed desktop app on bare WMs (i3, sway without xdg-utils); CI containers; PATH mangled by env cleaning or a wrapper script.","solutions":["Install an opener on Linux: xdg-utils (xdg-open) or glib (gio)","Check the app's PATH: launch it from a shell to compare, or fix the .desktop launcher's environment","Bypass the generic opener and invoke the specific target program (browser, editor CLI) directly","On WSL, prefer editor schemes that route through the direct CLI invocation path"],"exampleFix":"# before: no opener installed on a minimal distro\nopen https://example.com  # error: Errors occurred: [Failed to execute command ...]\n\n# after: install xdg-utils\nsudo apt install xdg-utils   # Debian/Ubuntu\nsudo pacman -S xorg-xdg-utils  # Arch","handlingStrategy":"fallback","validationCode":"import { access } from 'fs/promises';\n\nasync function hasOpener(bin: string): Promise<boolean> {\n  for (const dir of process.env.PATH!.split(':')) {\n    try {\n      await access(`${dir}/${bin}`);\n      return true;\n    } catch { /* keep checking */ }\n  }\n  return false;\n}\nconst genericOpenerOk = await hasOpener('xdg-open') || await hasOpener('gio');","typeGuard":null,"tryCatchPattern":"try {\n  await openThat(url);\n} catch (e) {\n  if (String(e).startsWith('Errors occurred')) {\n    // fallback: launch a concrete program yourself\n    await execFile('firefox', [url.toString()]);\n  } else throw e;\n}","preventionTips":["Ship or require xdg-utils on minimal Linux targets that use the opener","Test link opening on bare window managers, not just GNOME/KDE","Catch the aggregate error and fall back to invoking a known browser/editor binary"],"tags":["opener","linux","xdg-open","environment","rust"],"backgroundTag":"no-default-url-opener","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}