Skip to main content
Solutions to common problems, errors, and unexpected behavior.
Run the built-in diagnostic command:
chezmoi doctor
What it checks:
  • chezmoi version
  • Configuration file location and validity
  • Source directory location
  • Destination directory (usually home)
  • Editor configuration
  • Merge tool configuration
  • Password manager availability
  • Git configuration
  • And more…
Understanding the output:
  • ok - Everything is fine
  • warning - Only a problem if you use that feature
  • error - Definite problem that needs fixing
Example output:
RESULT CHECK MESSAGE
ok     version v2.46.0
ok     os linux
ok     config-file ~/.config/chezmoi/chezmoi.toml
ok     source-dir ~/.local/share/chezmoi
ok     working-tree ~/.local/share/chezmoi
warning age-command age not found in $PATH
ok     git-command git
ok     merge-command vimdiff
chezmoi provides two levels of debugging output:Verbose mode (recommended first):
chezmoi --verbose apply
chezmoi --verbose diff
chezmoi -v add ~/.bashrc  # Short form
This shows:
  • What chezmoi is doing
  • Files being read/written
  • Scripts being executed
  • External commands being run
Debug mode (very detailed):
chezmoi --debug apply
chezmoi --debug diff
This shows:
  • Step-by-step execution
  • Template evaluation
  • File comparisons
  • Internal state changes
  • Very detailed information
Debug a specific file:
chezmoi --verbose apply ~/.bashrc
chezmoi --debug execute-template < ~/.local/share/chezmoi/dot_bashrc.tmpl
This happens when your pager doesn’t pass through ANSI color codes. You’ll see output like ESC[37m instead of colors.Quick fix - Set LESS environment variable:
export LESS=-R
Add this to your ~/.bashrc or ~/.zshrc.Permanent fix - Configure chezmoi:
~/.config/chezmoi/chezmoi.toml
pager = "less -R"
Alternative solutions:Disable colors:
chezmoi diff --color=false
Disable pager:
chezmoi diff --no-pager
Or in config:
~/.config/chezmoi/chezmoi.toml
[diff]
    pager = ""
For other pagers:
  • bat: Use bat --paging=always
  • most: Already handles colors correctly
  • Custom pager: Ensure it supports ANSI codes
This happens when your editor command exits immediately (forking to background) instead of waiting for you to finish editing.The warning:
chezmoi: warning: $EDITOR returned in less than 1s
What’s happening:
  1. chezmoi creates a temporary file
  2. Your editor command starts and immediately returns
  3. chezmoi thinks you’re done and deletes the temp file
  4. Your editor (running in background) opens a now-deleted file
  5. You see a blank buffer
Solutions by editor:VSCode:
export EDITOR="code --wait"
Or in config:
~/.config/chezmoi/chezmoi.toml
[edit]
    command = "code"
    args = ["--wait"]
Vim:
export EDITOR="vim -f"
Or:
~/.config/chezmoi/chezmoi.toml
[edit]
    command = "vim"
    args = ["-f"]
Sublime Text:
export EDITOR="subl -w"
Neovim: Usually works by default, but if needed:
export EDITOR="nvim"
The key: Your editor command must block until you close the file.
This happens when your system umask is 002 (group-writable by default) instead of the more common 022.SSH requires strict permissions:
  • ~/.ssh/config must not be group or world writable
  • SSH will refuse to use it if permissions are wrong
Solution - Set chezmoi’s umask:
~/.config/chezmoi/chezmoi.toml
umask = 0o022
This ensures all files created by chezmoi follow this umask.Apply the fix:
chezmoi apply
Check permissions:
ls -la ~/.ssh/config
# Should show: -rw-r--r-- (644)
Note: This umask applies to all files managed by chezmoi, not just SSH config.
This error occurs when using a statically-compiled chezmoi binary (built with musl) on a system using LDAP or NIS for user management.Why it happens:
  • Static binaries with musl can’t dynamically load LDAP/NIS libraries
  • Your system needs these libraries to look up user information
Solution:Install a dynamically-linked package for your distribution instead:Debian/Ubuntu:
sudo apt install chezmoi
Fedora:
sudo dnf install chezmoi
Arch Linux:
sudo pacman -S chezmoi
These packages are linked against glibc and include LDAP/NIS support.Don’t use: The statically-compiled binary from GitHub releases on LDAP/NIS systems.If the problem persists, open an issue.
This error occurs when another chezmoi instance is running and holding the lock.Full error:
chezmoi: timeout obtaining persistent state lock
Common causes:
  1. Another chezmoi command is running
    • Check for background chezmoi processes
    • Look in other terminal windows
  2. Script calling chezmoi
    • A run_ script is invoking chezmoi
    • Creates a deadlock (chezmoi waiting for itself)
  3. Stale lock from crashed process
    • chezmoi crashed without releasing lock
    • Lock file persists
Solutions:Find running chezmoi processes:
ps aux | grep chezmoi
Kill if necessary:
killall chezmoi
Check for scripts calling chezmoi:
chezmoi cd
grep -r "chezmoi" run_*
Understanding locks:
  • Write lock: add, apply, edit, forget, import, init, state, unmanage, update
  • Read lock: diff, status, verify
  • Multiple readers OK, but only one writer
The lock file is at ~/.config/chezmoi/chezmoistate.boltdb.
This error means your script has a newline before the shebang (#!).Problem script:
run_once_setup.sh.tmpl
{{ if eq .chezmoi.os "linux" }}
#!/bin/bash
echo "Setting up Linux"
{{ end }}
This creates:

#!/bin/bash
The blank line breaks the shebang.Solution - Add dash to trim whitespace:
run_once_setup.sh.tmpl
{{ if eq .chezmoi.os "linux" -}}
#!/bin/bash
echo "Setting up Linux"
{{ end }}
The - before }} suppresses the trailing newline.Now creates:
#!/bin/bash
echo "Setting up Linux"
General rule: Use - to trim whitespace in templates:
  • {{- trims whitespace before
  • -}} trims whitespace after
This occurs when your /tmp directory is mounted with the noexec option, preventing script execution.Full error:
chezmoi: fork/exec /tmp/XXXXXXXXXX.XX: permission denied
Check if /tmp is noexec:
mount | grep /tmp
# Look for "noexec" in the output
Solution - Use a different temp directory:
~/.config/chezmoi/chezmoi.toml
scriptTempDir = "~/tmp"
Create the directory:
mkdir -p ~/tmp
Now chezmoi will write scripts to ~/tmp instead of /tmp.Why this happens:
  • chezmoi needs to write scripts to a temp location
  • Scripts might be templates or encrypted
  • Must be executable to run
  • /tmp with noexec prevents this
This error occurs when you try to add a file to a directory that only exists in .chezmoiexternal.* but not in your source directory.Example scenario:.chezmoiexternal.toml has:
[".config/nvim"]
    type = "git-repo"
    url = "https://github.com/NvChad/NvChad.git"
Then you try:
chezmoi add ~/.config/direnv/direnvrc
Error:
chezmoi: mkdir /home/user/.local/share/chezmoi/dot_config/direnv: no such file or directory
Why: The dot_config directory doesn’t exist in source because it’s external-only.Solution - Create placeholder directory:
chezmoi cd
mkdir -p dot_config
touch dot_config/.keep
Now the add command works:
chezmoi add ~/.config/direnv/direnvrc
See issue #2006 for details.
This is a long-standing bug in snap, not chezmoi.Error when using redirection:
chezmoi apply <file.txt  # Fails
chezmoi diff >output.txt  # Fails
Workarounds:For stdin:
# Instead of:
chezmoi apply <file.txt

# Use:
cat file.txt | chezmoi apply
For stdout:
# Instead of:
chezmoi diff >output.txt

# Use one of:
chezmoi diff -o output.txt
chezmoi diff --output=output.txt
chezmoi diff | tee output.txt >/dev/null
Better solution - Don’t use snap:Install chezmoi via another method:
# Script install
sh -c "$(curl -fsLS get.chezmoi.io)"

# APT (if available)
sudo apt install chezmoi

# Homebrew
brew install chezmoi
See the install page for all options.
This occurs when using hardcoded interpreter paths that don’t exist on Nix or Termux.Problem script:
run_once_setup.sh
#!/bin/bash
echo "Setting up"
On Nix/Termux, /bin/bash doesn’t exist.Solution 1 - Use lookPath (recommended):Make the script a template:
run_once_setup.sh.tmpl
#!{{ lookPath "bash" }}
echo "Setting up"
This finds bash wherever it is on the system.Solution 2 - Use env (Nix):
run_once_setup.sh
#!/usr/bin/env bash
echo "Setting up"
Solution 3 - Hardcode Termux path:
run_once_setup.sh
#!/data/data/com.termux/files/usr/bin/bash
echo "Setting up"
For Python scripts:
run_once_setup.py.tmpl
#!{{ lookPath "python3" }}
print("Setting up")
Best practice: Always use lookPath in templates for maximum portability.

Build docs developers (and LLMs) love