.dotfiles Manual

Cookbook

Cookbook: Troubleshooting

Symptom → cause → fix.

Installation

Symptom: install.sh fails with "chezmoi not found"

Cause: /usr/local/bin or ~/.local/bin not in PATH at install time.

Fix:

export PATH="$HOME/.local/bin:$PATH"
# Re-run only the installer that was release-pinned and SHA256-verified.
bash /tmp/dotfiles-install.sh

Symptom: "could not create directory ~/.local/share/chezmoi"

Cause: Permission issue on ~/.local.

Fix:

mkdir -p ~/.local/share ~/.local/state ~/.local/bin
chmod 755 ~/.local ~/.local/share

Symptom: Install hangs at "Downloading chezmoi"

Cause: Slow network or corporate proxy.

Fix:

export https_proxy=$HTTP_PROXY  # if applicable
# Or pre-download chezmoi manually
brew install chezmoi            # macOS
apt install chezmoi             # Debian 13+

Apply / Sync

Symptom: dot apply reports "file modified, skipping"

Cause: Chezmoi detected local drift on a managed file.

Fix:

dot diff                    # see what differs
dot apply --force           # overwrite local
# OR
dot config add <path>              # import local change to source

Symptom: "template: error calling index"

Cause: A template references a missing data field.

Fix: Check that the field exists in defaults/.chezmoidata.toml or defaults/.chezmoidata/*.toml. Machine presets are [machines.<name>] tables in defaults/.chezmoidata/hardware.toml; a machine value that names no preset leaves index .machines .machine empty. For example:

chezmoi execute-template '{{ (index .machines "macbook-t2").scale }}'

Set machine in ~/.config/chezmoi/chezmoi.toml to a preset that exists (macbook-t2, surface-pro, geekom-a9), or leave it empty to use the [hardware] defaults:

[data]
machine = "macbook-t2"

Symptom: Apply succeeds but shell doesn't reflect changes

Cause: Cached init scripts are stale.

Fix:

dot shell clean
dot shell update --prewarm
exec $SHELL -l

Theme

Symptom: dot theme shows no themes

Cause: No wallpapers discovered, themes.toml not generated.

Fix:

dot theme rebuild --force

Symptom: dot theme <name> errors "Unknown command or theme"

Cause: Theme name doesn't exist in themes.toml.

Fix:

dot theme list            # see valid names
dot theme rebuild --force # regenerate if expected but missing

Symptom: macOS accent color doesn't update

Cause: System Settings UI cached the old value.

Fix: dot-theme-sync already runs killall -HUP cfprefsd, then killall on SystemUIServer, Dock and "System Settings". If it still doesn't refresh:

killall -KILL Dock SystemUIServer
sudo killall -KILL cfprefsd

Or log out and back in.

Symptom: Wallpaper not applying

Cause: Wrong format or missing DE support on Linux.

Fix:

# Check the wallpaper file exists
ls -la ~/Pictures/Wallpapers/

# On Linux, verify a HEIC to PNG conversion tool
command -v magick || command -v heif-convert || command -v convert
# Install if needed (Debian/Ubuntu):
sudo apt install imagemagick      # or libheif-examples for heif-convert

Symptom: Theme applies but Ghostty doesn't reload

Cause: Ghostty DBus or SIGUSR2 signaling failed.

Fix:

# Restart Ghostty manually, or:
pkill -USR2 ghostty 2>/dev/null
# Or quit+relaunch the app

Secrets

Symptom: "could not decrypt: no age key"

Cause: The age identity is missing or unreadable. chezmoi reads ~/.config/chezmoi/key.txt (the age.identity in ~/.config/chezmoi/chezmoi.toml); SOPS reads ~/.config/sops/age/keys.txt.

Fix:

ls -la ~/.config/chezmoi/key.txt ~/.config/sops/age/keys.txt
# Should be: -rw------- 1 user user
chmod 600 ~/.config/chezmoi/key.txt ~/.config/sops/age/keys.txt

# If missing, restore from password manager or regenerate (requires re-encrypting all secrets)

Symptom: SOPS says "wrong recipient"

Cause: Your Age public key isn't listed in the file's recipients.

Fix:

# Add your public key to .sops.yaml
sops updatekeys path/to/file.sops.yaml

# Or, ask a recipient to re-encrypt for you

Symptom: Plaintext leak detected by gitleaks

Cause: A secret was committed to Git history.

Fix:

# Immediate mitigation
dot secret check        # confirm which file
git rm --cached <file>
echo "<file>" >> .gitignore
git commit -sS -m "fix(security): remove leaked file"

# Rotate the leaked secret upstream (it's now public)
# Rewrite Git history if needed (requires force-push):
git filter-repo --path <file> --invert-paths

Performance

Symptom: Shell startup >500ms

Cause: Heavy modules loaded synchronously.

Fix:

dot doctor perf measure --detailed
# Identify which module is slow

# Rebuild caches
dot shell update --prewarm

# Disable heavy modules temporarily
# Edit ~/.config/zsh/.zshrc.local (or equivalent) to skip them

Symptom: dot doctor score show reports a low score

Cause: Multiple health issues.

Fix:

dot doctor status             # see every check
dot doctor fix                # auto-fix what's possible
dot doctor                    # recheck

Symptom: Mise tools not found

Cause: Mise shim not activated.

Fix:

eval "$(mise activate zsh)"  # or fish, bash
dot doctor                    # confirm

Build Artifacts

Symptom: Cargo builds into the project's ./target

Cause: This is the default. ~/.cargo/config.toml deliberately sets no shared target-dir, because Cargo locks the target directory and one shared path makes builds in different projects wait on each other. sccache (when installed) still shares compiled dependencies across projects.

Fix (optional, zsh): keep the output out of the repository by pointing ./target at the private build cache:

rust-target-tmp          # target -> $DOT_BUILD_ROOT/<repo-name>

Symptom: $DOT_BUILD_ROOT is unset or missing

Cause: The shell predates the change, or mise is not activated. DOT_BUILD_ROOT is ~/.cache/dot/builds (under XDG_CACHE_HOME). mise exports it, and zsh and fish set it on start; the Go, pip, uv and Zig caches live below it.

Fix:

exec $SHELL -l
mise env | grep DOT_BUILD_ROOT

Fleet

Symptom: dot fleet apply hangs

Cause: A fleet host is unreachable.

Fix:

dot fleet apply --dry-run   # list the resolved hosts and their SSH targets

# Check connectivity to each SSH target
for target in user@laptop.local user@desktop.local; do
  ssh -o ConnectTimeout=5 "$target" 'echo OK' || echo "FAIL: $target"
done

# Apply to the reachable hosts one at a time, or remove the unreachable
# ones from ~/.config/dotfiles/fleet.toml temporarily
dot fleet apply --host laptop

Symptom: Git shows a signed commit as untrusted

Cause: The signer's SSH public key is not in ~/.config/git/allowed_signers (git's gpg.ssh.allowedSignersFile).

Fix: That file is managed by chezmoi, so add the key to the source, defaults/dot_config/git/allowed_signers.tmpl, as <email> ssh-ed25519 <key>, then:

dot apply
git log --format='%G? %h %s' -5   # G = good, trusted signature

CI

Symptom: PR fails on "Lint / Shell (Zero Warnings)"

Cause: shfmt formatting differs from canonical.

Fix:

shfmt -w -i 2 -ci scripts/**/*.sh install.sh defaults/.chezmoitemplates/**/*.sh
# Commit the changes

Symptom: PR fails at the "Enforce module coverage" step

Cause: New code added without tests. The gate runs in "Test / Unit Tests" (100% in ci-enforced.yml) and "Test / Unit" (98% in ci.yml).

Fix:

MIN_COVERAGE=100 ./tests/framework/module_coverage.sh
# Lists uncovered modules

# Add a test in tests/unit/<domain>/test_<module>.sh

Symptom: Checkov SARIF upload times out

Cause: Known infrastructure flake (Azure runner slow apt mirrors).

Fix: The workflow already guards this with hashFiles('reports/checkov.sarif'). If you see this after the guard was added, check the Checkov step output for errors.

Getting More Help

  1. Check FAQ
  2. Read the relevant concept chapter
  3. Open an issue: https://github.com/sebastienrousseau/dotfiles/issues

When filing an issue, include:

dot doctor --json
dot version
uname -a
chezmoi --version

See Also