Troubleshooting¶
Common failures and how to fix them. Most problems surface through
verify.sh or the summary at
the end of an update.sh run. When in doubt, start with the health check:
bash ~/dotfiles/verify.sh
bash ~/dotfiles/scripts/status.sh # quick repo + last-update snapshot (dotstatus)
FAQ¶
How do I change my machine's profile without re-bootstrapping?
Use the dotprofile alias, then re-apply:
dotprofile set work # persist the new profile
zsh ~/dotfiles/install.sh # re-link dotfiles for it
bash ~/dotfiles/update.sh # re-run packages + health check
Is it safe to re-run bootstrap / install / update?
Yes. All of them are idempotent — already-installed tools are skipped and correct symlinks are left alone. Re-running is the normal way to heal a machine.
Where are my old dotfiles after bootstrap?
install.sh backs up any real file it replaces to
~/.dotfiles_backup/<timestamp>/. verify.sh warns when backups are older
than 30 days; clear them with rm -rf ~/.dotfiles_backup.
Why didn't my change to ~/.zshrc stick?
~/.zshrc is a symlink into the repo. Machine-specific config belongs in
~/.zshrc.local (seeded from a template on first bootstrap), which is not
tracked.
Failed update or rebase¶
update.sh pulls with git pull --rebase --autostash. It is defensive by
design:
- Uncommitted changes in the dotfiles repo → the pull step is skipped with a warning so it never starts a rebase it can't finish. Commit or stash your work, or force it:
- A pull that fails mid-rebase →
update.shautomatically runsgit rebase --abort, leaving the repo exactly as it was. Resolve manually: - A failed step does not abort the run.
update.shcollects failures and reports them in the final banner and inlogs/update.status. Inspect details with:
Broken symlinks¶
A broken symlink is the only condition verify.sh treats as an error
(exit 1). It usually means a file was moved/renamed in the repo, or a link was
deleted. Re-running the installer heals them:
bash ~/dotfiles/verify.sh # lists each broken link
zsh ~/dotfiles/install.sh # re-create links for the active profile
If verify.sh flags a link you expected to be skipped, check the tags
column in config/symlinks.map — the link
only applies to profiles that match its tag, and verify.sh filters by the
active profile, so an intentionally-skipped link is never reported.
Missing tools¶
verify.sh checks a list of required tools (brew, mise, git, gh,
delta, lazygit, rg, fd, bat, fzf, zoxide, rustup/rustc/cargo,
jq, shellcheck, direnv, starship, pre-commit, yarn). A missing tool
is a warning, not an error. Re-run bootstrap to install the gaps:
bash ~/dotfiles/bootstrap.sh # re-installs from the profile Brewfiles
# or install one package directly:
brew install <tool>
If a command exists but isn't found in a new shell, confirm mise is active
(eval "$(mise activate zsh)" runs from home/zshrc) and that tool shims are on
PATH — open a fresh shell or source ~/.zshrc.
Brewfile drift¶
verify.sh warns when installed packages no longer match the profile's
Brewfiles (core + Brewfile.personal + Brewfile.work as applicable). To
reconcile:
# Install anything declared but missing:
brew bundle --file=~/dotfiles/Brewfile
brew bundle --file=~/dotfiles/Brewfile.personal # GUI profiles
brew bundle --file=~/dotfiles/Brewfile.work # work profile
# See exactly what differs (declared vs installed):
brew bundle check --file=~/dotfiles/Brewfile --verbose
If you installed something you want to keep, add it to the appropriate Brewfile
so it becomes tracked; otherwise brew uninstall it.
GitHub CLI authentication¶
bootstrap.sh runs gh auth login if gh is installed but not authenticated.
If gh commands fail later:
gh auth status # check current state
gh auth login # re-authenticate (choose SSH for git operations)
gh auth setup-git # configure git to use gh credentials
Because ~/.gitconfig is a real file (a thin include of the tracked config),
gh auth setup-git writes safely into it without touching the repo. If git
operations break after auth changes, run bash ~/dotfiles/verify.sh — the
"Git config include" check confirms the include is intact and git config
parses cleanly.
mise runtimes¶
verify.sh warns if a runtime declared in
config/mise.toml isn't installed. Install
the declared set:
mise install # install everything in config/mise.toml
mise current # show active versions
mise use --global node@22 # pin/switch a global version
Compiling runtimes (especially Ruby) can take several minutes. If a runtime
isn't picked up, ensure mise is activated in your shell and reopen the
terminal.
Encrypted secrets (sops + age)¶
age key not foundwhen editing/decrypting → generate or restore your key: Then make sure your public key is a recipient in.sops.yaml. See Encrypted Secrets.sopscan't decrypt a file → your public key isn't (or no longer is) a recipient. Have an existing holder add it and re-key:- Lost private key → encrypted files are unrecoverable. Rotate the affected
credentials and generate a new key. Always back up
keys.txtto a password manager.
See Encrypted Secrets for the full setup and safety model.
Scheduled updates¶
Daily updates run via a launchd agent installed by scripts/setup-scheduler.sh
(runs update.sh at 9 AM). Because launchd does not source your shell rc,
the job reads ~/.config/dotfiles/update.conf for defaults like
NO_UPGRADE=true.
bash ~/dotfiles/scripts/setup-scheduler.sh # install (9 AM daily)
bash ~/dotfiles/scripts/setup-scheduler.sh --no-upgrade # scheduled run skips upgrades
bash ~/dotfiles/scripts/setup-scheduler.sh --uninstall # remove the job
If scheduled runs aren't happening:
launchctl print gui/$(id -u)/com.dotfiles.update # is the agent loaded?
cat ~/dotfiles/logs/update.log # what happened last run
cat ~/dotfiles/logs/update.status # last result + failed steps
Re-installing is idempotent (it boots out any existing agent first). For a
machine-wide default that also applies to manual runs, set NO_UPGRADE=true in
~/.config/dotfiles/update.conf rather than only on the scheduled job.
Pre-flight failures¶
bootstrap.sh runs scripts/preflight.sh first.
Critical errors (not macOS, no internet, <5 GB disk, unwritable $HOME,
conflict markers in tracked dotfiles) abort the run; warnings prompt to
continue. Run it standalone any time:
bash ~/dotfiles/scripts/preflight.sh # 0 = ok, 2 = warnings, 1 = errors
bash ~/dotfiles/scripts/preflight.sh --strict # treat warnings as errors
If you must proceed past pre-flight (not recommended):
Docs / Pages build issues¶
The docs site is built with MkDocs Material and deployed to GitHub Pages. The
build runs in strict mode, which fails on any warning — most commonly a
page missing from the nav in mkdocs.yml, or a broken relative link. Build
locally before pushing:
uvx --with mkdocs-material mkdocs build --strict # must finish with zero warnings
uvx --with mkdocs-material mkdocs serve # live preview at localhost:8000
If the build fails:
- "is not found in the documentation files" / not in nav → add the new page
to
nav:inmkdocs.yml. - "contains a link … that is not found" → fix the relative link so it resolves to an existing page.
See Contributing for the full docs workflow.