twpayne/chezmoi · error
%s: not allowed in %s directory
Error message
%s: not allowed in %s directory
What it means
Files inside the .chezmoiexternal source directory whose names begin with chezmoi's reserved Prefix (".") are not permitted. The walk over the externals directory stat()s each entry and rejects entries named like internal chezmoi files, since they could be confused with chezmoi control files.
Source
Thrown at internal/chezmoi/sourcestate.go:1490
s.externals[targetRelPath] = append(s.externals[targetRelPath], &external)
}
return nil
}
// addExternalDir adds all externals in externalsDirAbsPath to s.
func (s *SourceState) addExternalDir(ctx context.Context, externalsDirAbsPath AbsPath) error {
walkFunc := func(ctx context.Context, externalAbsPath AbsPath, fileInfo fs.FileInfo, err error) error {
if externalAbsPath == externalsDirAbsPath {
return nil
}
if err == nil && fileInfo.Mode().Type() == fs.ModeSymlink {
fileInfo, err = s.system.Stat(externalAbsPath)
}
switch {
case err != nil:
return err
case strings.HasPrefix(fileInfo.Name(), Prefix):
return fmt.Errorf("%s: not allowed in %s directory", externalAbsPath, externalsDirName)
case strings.HasPrefix(fileInfo.Name(), ignorePrefix):
if fileInfo.IsDir() {
return fs.SkipDir
}
return nil
case fileInfo.Mode().IsRegular():
parentAbsPath, _ := externalAbsPath.Split()
return s.addExternal(externalAbsPath, parentAbsPath.Dir())
case fileInfo.IsDir():
return nil
default:
return &UnsupportedFileTypeError{
absPath: externalAbsPath,
mode: fileInfo.Mode(),
}
}
}
return concurrentWalkSourceDir(ctx, s.system, externalsDirAbsPath, walkFunc)View on GitHub (pinned to f901167e46)
Solutions
- Remove or rename the dot-prefixed file inside the .chezmoiexternal.d directory
- Add the file to .gitignore so it never enters the source state
- If it must be tracked, rename it without a leading dot
Example fix
# before .chezmoiexternal.d/ .DS_Store browser.toml # after (delete .DS_Store) .chezmoiexternal.d/ browser.toml
Defensive patterns
Strategy: validation
Validate before calling
for _, f := range entriesOfExternalsDir {
if strings.HasPrefix(f, ".") {
fmt.Printf("remove dot-prefixed file %s from .chezmoiexternal.d\n", f)
}
} Prevention
- Never place dotfiles in .chezmoiexternal.d
- Add .DS_Store etc. to .gitignore
When it happens
Trigger: Placing a file or directory whose name starts with "." (the Prefix) inside the .chezmoiexternal.d directory while chezmoi walks the externals directory (sourcestate.go:1490).
Common situations: Hidden files (e.g. .DS_Store, .gitignore) extracted or committed inside .chezmoiexternal.d, or accidentally copying dotfiles into the externals directory.
Related errors
- empty directory name
- empty filename
- %s: parent directory not in source state
- %s: not a script
- %s: not a directory
AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01).
Data as JSON: /api/errors/c356c62dd94053ed.
Report an issue: GitHub.