-
Notifications
You must be signed in to change notification settings - Fork 610
Description
Describe the bug
chezmoi data will read .chezmoidata files inside external directories, but chezmoi apply will not.
When SourceState.templateDataOnly is true (e.g. when chezmoi data is used), the walkFunc defined in SourceState.Read will walk through external directories, calling addTemplateData on any .chezmoidata.$FORMAT files in those directories.
Conversely, if templateDataOnly is false, readExternalDir is used to process those files, which does not have special handling .chezmoidata (and other special) files. Then fs.SkipDir is returned, which prevents further recursing with walkFunc (which would have special handling for special fiels).
To reproduce
$ chezmoi cd
$ mkdir external_private
$ echo '{"nested": {"sentinel_value": "external data"}}' > external_private/.chezmoidata.json
$ echo '{{ .nested.sentinel_value }}' > ext-data.tmpl
$ chezmoi data | jq '.nested.sentinel_value'
"external data"
$ chezmoi execute-template "$(cat ext-data.tmpl)"; printf "\n"
external data
$ chezmoi diff > /dev/null # redirection not necessary, just suppressing other diff output
chezmoi: ext-data: template: ext-data.tmpl:1:10: executing "ext-data.tmpl" at <.nested.sentinel_value>: map has no entry for key "nested"
$ Expected behavior
The template data available to each command should be the same.
I'd personally prefer if external .chezmoidata files were processed, but either way consistency is what matters, to avoid issues debugging (where this inconsistency surprised me).
Output of command with the --verbose flag
No different.
Notable partial output from running chezmoi data --debug:
time=2026-03-04T16:23:12.427-05:00 level=INFO msg=ReadDir component=system name=/Users/mjec/.local/share/chezmoi/external_private
time=2026-03-04T16:23:12.427-05:00 level=INFO msg=ReadDir component=system name=/Users/mjec/.local/share/chezmoi/external_private/.chezmoidata
time=2026-03-04T16:23:12.427-05:00 level=INFO msg=ReadFile component=system name=/Users/mjec/.local/share/chezmoi/external_private/.chezmoidata/claude-plugins.json size=1183 data="{\n \"llms\": {\n \"claude\": {\n \"marketplaces\": {\n \"e..."
Whereas chezmoi diff --debug does not show anything about external_private.
Output of chezmoi doctor
Details
$ chezmoi doctor
RESULT CHECK MESSAGE
ok version v2.69.4, commit c4c669c9f2f329233a85802014d26fba3c58a4a4, built at 2026-02-11T08:59:37Z, built by Homebrew
ok latest-version v2.69.4
ok os-arch darwin/arm64
ok uname Darwin MacBook-Pro-9.local 25.3.0 Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:15 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T6000 arm64
ok go-version go1.25.7 (gc)
ok executable /opt/homebrew/bin/chezmoi
ok upgrade-method brew-upgrade
ok config-file found ~/.config/chezmoi/chezmoi.toml, last modified 2026-03-04T10:22:15-05:00
warning source-dir ~/.local/share/chezmoi is a git working tree (dirty)
warning suspicious-entries ~/.local/share/chezmoi/.git/fsmonitor--daemon.ipc [submodule fsmonitor demon ipc entries edited out]
warning working-tree ~/.local/share/chezmoi is a git working tree (dirty)
ok dest-dir ~ is a directory
ok hardlink created hardlink from ~/.local/share/chezmoi to /var/folders/4d/h66416yd4y5d5lyg2f5jphzr0000gp/T/
ok symlink created symlink from .new-name to .old-name
ok umask 022
ok cd-command found /bin/zsh
ok cd-args /bin/zsh
info diff-command not set
ok edit-command found /Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code
ok edit-args code --wait --new-window
ok git-command found /opt/homebrew/bin/git, version 2.53.0
ok merge-command found /opt/homebrew/bin/vimdiff
ok shell-command found /bin/zsh
ok shell-args /bin/zsh
ok age-command found /opt/homebrew/bin/age, version 1.3.1
info gpg-command gpg not found in $PATH
info pinentry-command not set
ok 1password-command found /opt/homebrew/bin/op, version 2.32.1
info bitwarden-command bw not found in $PATH
info bitwarden-secrets-command bws not found in $PATH
info dashlane-command dcli not found in $PATH
info doppler-command doppler not found in $PATH
info gopass-command gopass not found in $PATH
info keepassxc-command keepassxc-cli not found in $PATH
info keepassxc-db not set
info keeper-command keeper not found in $PATH
info lastpass-command lpass not found in $PATH
info pass-command pass not found in $PATH
info passhole-command ph not found in $PATH
info protonpass-command pass-cli not found in $PATH
info rbw-command rbw not found in $PATH
info vault-command vault not found in $PATH
info secret-command not set
$ Additional context
I also asked about this in a discussion post before I'd narrowed it down to a bug.
I tracked this down using Claude Code, but verified its output by looking at the code, and wrote up this bug report without the aid of an LLM.