{"record":{"id":"25348414763d339b","repo":"gitbutlerapp/gitbutler","slug":"can-only-open-the-gui-on-directories-not-dir","errorCode":null,"errorMessage":"Can only open the GUI on directories: '{not_dir}'","messagePattern":"Can only open the GUI on directories: '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/gui.rs","lineNumber":11,"sourceCode":"use anyhow::{Context as _, Result};\nuse but_path::AppChannel;\n\n/// Open the GitButler GUI application for `possibly_project_dir`,\n/// which must be a directory or trigger an error.\n///\n/// This expects that the GUI application is present and has correctly registered URL\n/// schemes for the different channels.\npub fn open(possibly_project_dir: &std::path::Path, new_window: bool) -> Result<()> {\n    if !possibly_project_dir.is_dir() {\n        anyhow::bail!(\n            \"Can only open the GUI on directories: '{not_dir}'\",\n            not_dir = possibly_project_dir.display()\n        );\n    }\n\n    let channel = AppChannel::new();\n    let absolute_path = std::fs::canonicalize(possibly_project_dir).with_context(|| {\n        format!(\n            \"Failed to canonicalize path before opening the GUI: {}\",\n            possibly_project_dir.display()\n        )\n    })?;\n    channel.open(&absolute_path, new_window)?;\n    Ok(())\n}\n","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but/src/command/gui.rs#L1-L27","documentation":"`but gui` opens the desktop app pointed at a project directory, relying on registered URL schemes per release channel. `open` validates that the given path is actually a directory and bails with the offending path if not, since the GUI can only be launched against a project/worktree directory.","triggerScenarios":"Running `but gui <path>` where path is a regular file, a broken symlink, a non-existent path, or a typo; also passing a deleted directory that was removed after shell completion cached it.","commonSituations":"Tab-completing onto a file instead of the repo folder; passing the repo's README or a subfile; running from a stale shell whose cwd directory was deleted; typos in the path.","solutions":["Pass the repository root directory (or a directory inside it) instead of a file","Verify the path exists and is a directory: test -d <path>","Recreate or re-clone the directory if it was deleted/moved"],"exampleFix":"// before\nbut gui ~/repos/myproj/README.md\n// after\nbut gui ~/repos/myproj","handlingStrategy":"validation","validationCode":"const fs = require('node:fs');\nfunction assertIsDirectory(p) {\n  if (!fs.statSync(p).isDirectory()) throw new Error(`Not a directory: ${p}`);\n}\n// call before: but gui <path>","typeGuard":"const isDir = (p) => { try { return require('node:fs').statSync(p).isDirectory(); } catch { return false; } };","tryCatchPattern":"try {\n  await openGui(projectPath);\n} catch (e) {\n  if (e.message.includes('Can only open the GUI on directories')) {\n    console.error(`Pass the repo directory, not: ${projectPath}`);\n  } else throw e;\n}","preventionTips":["Pass the repository root, never a file, to `but gui`","Validate paths with test -d in shell wrappers","Watch for stale cwd after deleting/moving the project directory"],"tags":["cli","gui","filesystem"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}