Repository navigation
Debugging
Something is wrong and you want to know why. This page shows where to look, in the order that usually finds the problem fastest: the error message, the web view tools, the Rust side, and a reproduction you can run again. It ends with the dead ends that cost us time before.
flowchart TD
Start["Something went wrong"] --> Toast{"Did a toast show<br/>an error?"}
Toast -->|"yes"| Kind{"AppError kind?"}
Kind -->|"command"| Term["Run the same git command<br/>in a terminal in that repository"]
Kind -->|"git or io"| Rust["Read the Rust code for that command"]
Kind -->|"invalid"| Input["Check the arguments the UI sent"]
Toast -->|"no"| Dev["Web Inspector, or ask the<br/>running app over MCP"]
Dev --> Repro["Reproduce with a demo script"]
Term --> Repro
Rust --> Repro
Input --> Repro
Repro --> Test["Write a failing test"]
Every failed command reaches the UI as AppError { kind, message } (see Backend). repoStore.run shows it as a toast titled <label> failed with the message below it. The kind tells you which layer failed:
| Kind | Meaning | Where to look |
|---|---|---|
command |
the git CLI exited with an error; the message is git's own output | run the same command in a terminal, in the same repository |
git |
a git2 (libgit2) call failed | the reader in src-tauri/src/git/ behind that command |
io |
a file could not be read or written | permissions, a missing folder, a path that changed |
invalid |
the backend refused the input, like a path with .. or an unknown config name |
the arguments the UI passed |
For command errors, the terminal is your best friend. If git push fails the same way there, the problem is in the repository or your git setup, not in the app. The exact git arguments for each command are listed in Commands and Events.
Debug builds (everything bun tauri dev runs) include the Safari Web Inspector. Open it with Cmd+Option+I, or right-click an area that has no custom menu and choose Inspect Element. Release builds leave it out, because the tauri crate is built without its devtools feature.
What it is good for:
- Console: uncaught errors and failed promises from the UI.
- Elements: check which CSS token a color comes from, or why a layout wraps.
-
Network: the update check's call to
api.github.com. -
Trying a command by hand:
await window.__TAURI_INTERNALS__.invoke("get_status", { repoPath: "/tmp/conflict-demo" })calls the backend directly. This is Tauri's internal object, so use it only for poking around, never in app code (that is whatapi.tsis for).
Svelte changes reload instantly, so you can add a temporary console.log, look, and remove it. Never commit one.
The terminal running bun tauri dev shows Rust compile errors and any panic, with the file and line. The backend has no general log: errors travel to the UI as AppError. Two switches record more: the Git Console (Settings, Git) keeps the git commands the app ran, and the memory log (Settings, Automation) writes memory changes to ~/.nibtree/logs/memory.log (cut at 5 MB, the previous one kept as memory.log.1). While you debug, a temporary eprintln!("{repo_path}") prints to that terminal. Remove it before you commit.
-
Backtraces: start with
RUST_BACKTRACE=1 bun tauri dev. -
Panics in dev inside
commands::blockingcome back as aninvaliderror, "Background task failed", instead of killing the app. -
Panics in release abort the whole app, because the release profile sets
panic = "abort". That is why the code never callsunwrapon data from users or repositories: use?,.ok()or a default instead.
With the MCP server or the command line tool on (Settings, Automation), an agent or a script can look at the real window and measure it: get_app_state for what is on screen, inspect_elements for computed styles and sizes, take_screenshot, and get_memory_usage, the memory recorder, get_ui_performance and scroll_view for memory and frames. For example, nibtree cli call get_app_state prints the open tabs and panels. Recipes and two worked examples are in Debugging with MCP.
A bug you can repeat is half fixed. Build a throwaway repository instead of testing on real work:
scripts/make-conflict-repo.sh /tmp/conflicts # every conflict type, stopped in a merge
scripts/make-conflict-repo.sh /tmp/rebase --rebase # the same, stopped in a rebase
scripts/make-workspace-demo.sh /tmp/workspace # nested, conflicted and clean repositories
bun tauri dev -- -- /tmp/conflictsOnce you know the steps, turn them into a failing test with TestRepo (Rust) or a pure .ts module (Vitest), then fix it. See Testing.
Sometimes a normal browser's devtools are easier, or you want a script to click through the UI. The dev-only IPC bridge lets a browser page use the backend of the running app:
GM_IPC_BRIDGE=1 bun tauri dev
# keep the app window open, then visit http://127.0.0.1:1420/?ipc-bridge in a browserBe careful: every command the page sends runs in the app for real, with your own ~/.nibtree settings unless scripts/screenshots.ts overrides them. Open only demo repositories, and stop the app when you are done. Only terminal-exited and git-command reach the page; other backend events such as repo-changed do not, so reload it after changes on disk. How the bridge works is in Architecture.
"Port 1420 is already in use". An old dev session left Vite running. Vite uses strictPort because Tauri loads the UI from exactly that address. Find the process with lsof -i :1420, stop it, and start again.
Strange errors from Vite or svelte-kit. You probably ran npm, npx or node. The system Node is too old. Use bun and the scripts in package.json, which run on bun --bun.
A hook fails with "command not found", or git is not found. Apps started from Finder get a tiny PATH. git/cli.rs asks your login shell for the real one ($SHELL -l -c), with a 3 second limit. If your shell startup is slow or prints errors, it falls back to Homebrew paths plus the current PATH. Check with $SHELL -l -c 'echo $PATH'. The git binary is the first of /opt/homebrew/bin/git, /usr/local/bin/git and /usr/bin/git that exists.
Push or fetch fails with "terminal prompts disabled". That is on purpose: GIT_TERMINAL_PROMPT=0, because a GUI cannot answer a password prompt and git would wait forever. Set up a credential helper (for example the macOS keychain) or an SSH agent, and check that git push works in a terminal without asking anything.
An action seems to hang. A slow hook runs exactly as in the terminal, so the busy label stays until it finishes. Editors never open: GIT_EDITOR and GIT_SEQUENCE_EDITOR are true (Interactive Rebase sets its own sequence editor, which copies the prepared todo list).
The UI does not refresh after a change. The watcher drops paths the repository ignores and noise inside .git (objects/, logs/, lfs/, *.lock). Check that the file is not ignored and that it belongs to the repository you expect: with nested repositories, the deepest one wins.
Settings do not stick. If ~/.nibtree/settings.json has invalid JSON, the app uses defaults, shows the error in Settings and never overwrites the file. Fix the JSON by hand.
Port 1420 cost us restarts more than once. A different port is tempting, but Tauri's devUrl and Vite's strictPort use 1420 on purpose. Stopping the stale process is the real fix (see CLAUDE.md, Gotchas).
The memory readout found no helpers in a dev build. A terminal launch makes the terminal the app's "responsible" process, so numbers from bun tauri dev are approximate. The story is in How memory is measured.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode