twpayne/chezmoi · error
%s: parent directory not in source state
Error message
%s: parent directory not in source state
What it means
During 'chezmoi add', after computing the parent of each target in the source state tree, chezmoi requires that the parent directory of the target already exists as a SourceStateEntry (i.e. is tracked or implicitly present in the source state). If the walk ends without finding the parent directory entry, it cannot determine where to place the new source file, so it fails.
Source
Thrown at internal/chezmoi/sourcestate.go:496
}
continue
}
switch sourceStateDir, ok := node.SourceStateEntry.(*SourceStateDir); {
case i != len(nodes)-1 && !ok:
panic(fmt.Errorf("nodes[%d]: unexpected non-terminal source state entry, got %T", i, node.SourceStateEntry))
case ok && sourceStateDir.attr.External:
targetRelPathComponents := targetRelPath.SplitAll()
externalDirRelPath := EmptyRelPath.Join(targetRelPathComponents[:i]...)
externalDirRelPaths.Add(externalDirRelPath)
if options.Errorf != nil {
options.Errorf("%s: skipping entries in external_ directory\n", externalDirRelPath)
}
continue DEST_ABS_PATH
}
}
parentSourceRelPath = nodes[len(nodes)-1].SourceStateEntry.SourceRelPath()
} else {
return fmt.Errorf("%s: parent directory not in source state", destAbsPath)
}
nonEmptyDirs.Add(parentSourceRelPath)
destAbsPathInfo := destAbsPathInfos[destAbsPath]
var actualStateEntry ActualStateEntry
var newSourceStateEntry SourceStateEntry
if destAbsPathInfo == nil {
// If the destination does not exist then create a new, empty file.
_, relPath := destAbsPath.Split()
actualStateEntry = &ActualStateAbsent{
absPath: destAbsPath,
}
fileAttr := FileAttr{
TargetName: relPath.String(),
Type: SourceFileTypeFile,
Encrypted: options.Encrypt,
Empty: true,
Template: options.Template,View on GitHub (pinned to f901167e46)
Solutions
- Check .chezmoiignore (in the source directory) for patterns excluding the target's parent directory and remove/adjust them.
- Add the parent directory first (touch a file inside it via 'chezmoi add' of a sibling tracked file) so a directory entry exists.
- Verify the source directory structure with 'chezmoi managed' and re-add from a clean state if the source tree was manually edited.
Example fix
// before: dot_config/chezmoi in .chezmoiignore, then $ chezmoi add ~/.config/chezmoi/extra.conf // after: remove 'dot_config/chezmoi' from .chezmoiignore, then re-run chezmoi add
Defensive patterns
Strategy: validation
Validate before calling
parent=$(dirname "${1#$HOME/}")
if chezmoi managed | grep -q "^$parent$"; then
chezmoi add "$1"
else
echo "parent $parent not managed/ignored? check .chezmoiignore" >&2
fi Try / catch
// Go caller
if err := sourceState.Update(...); err != nil {
if strings.Contains(err.Error(), "parent directory not in source state") {
// add parent dir entry or fix .chezmoiignore, then retry
}
} Prevention
- Keep .chezmoiignore aligned with what you add
- Track parent directories before nested files
- Avoid manual edits that desync the source tree
When it happens
Trigger: Adding a file whose parent directory cannot be resolved in the source state tree, e.g. adding a deeply nested path when an intermediate directory entry is missing from the source state build (nodes list exhausted without a SourceStateEntry carrying SourceRelPath).
Common situations: Adding a path whose parent is ignored via .chezmoiignore; adding files into directories that exist on disk but are excluded from the source state; inconsistent source state after manual edits to the source directory.
Related errors
- %s: not a directory
- empty directory name
- empty filename
- %s: cannot add chezmoi's config file to chezmoi, use a confi
- %s: cannot add chezmoi file to chezmoi (%s is protected)
AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01).
Data as JSON: /api/errors/b6fd1f040a77c0f9.
Report an issue: GitHub.