helm/helm · error
cannot load a directory
Error message
cannot load a directory
What it means
Error from LoadFile in pkg/chart/v2/loader/archive.go. LoadFile is strictly the file (archive) loader: it stats the path and refuses directories outright before attempting to open/read an archive. The generic entry points Loader()/Load() exist precisely to pick DirLoader vs FileLoader based on os.Stat, so seeing this error means the directory-specialized path was bypassed.
Source
Thrown at pkg/chart/v2/loader/archive.go:43
"helm.sh/helm/v4/pkg/chart/loader/archive"
chart "helm.sh/helm/v4/pkg/chart/v2"
)
// FileLoader loads a chart from a file
type FileLoader string
// Load loads a chart
func (l FileLoader) Load() (*chart.Chart, error) {
return LoadFile(string(l))
}
// LoadFile loads from an archive file.
func LoadFile(name string) (*chart.Chart, error) {
if fi, err := os.Stat(name); err != nil {
return nil, err
} else if fi.IsDir() {
return nil, errors.New("cannot load a directory")
}
raw, err := os.Open(name)
if err != nil {
return nil, err
}
defer raw.Close()
err = archive.EnsureArchive(name, raw)
if err != nil {
return nil, err
}
c, err := LoadArchive(raw)
if err != nil {
if errors.Is(err, gzip.ErrHeader) {
return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %w)", name, err)
}View on GitHub (pinned to 2a29f1770b)
Solutions
- Use the dispatching API: c, err := c2loader.Loader(path) then l.Load() — it selects DirLoader for directories and FileLoader for files
- Or branch explicitly: if fi.IsDir() { c2loader.LoadDir(path) } else { c2loader.LoadFile(path) }
- Validate the user-supplied path is a regular file before calling LoadFile, and surface a clear message otherwise
Example fix
// before
func loadChart(p string) (*chart.Chart, error) {
return c2loader.LoadFile(p)
}
// after
func loadChart(p string) (*chart.Chart, error) {
l, err := c2loader.Loader(p)
if err != nil {
return nil, err
}
return l.Load()
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the path type before choosing the loader
func isRegularFile(p string) (bool, error) {
fi, err := os.Stat(p)
if err != nil {
return false, err
}
return !fi.IsDir(), nil
} Try / catch
l, err := c2loader.Loader(path) // dispatches DirLoader vs FileLoader via os.Stat
if err != nil {
return nil, err
}
c, err := l.Load()
if err != nil {
if strings.Contains(err.Error(), "cannot load a directory") {
return nil, fmt.Errorf("%s is a directory — use LoadDir", path)
}
return nil, err
} Prevention
- Prefer the dispatching Loader()/Load() APIs over hardcoding LoadFile when input can be a directory
- Validate user-supplied chart paths with os.Stat before loading and give an actionable message
- If a download step precedes loading, assert the output path is a regular non-empty file
When it happens
Trigger: Calling c2loader.LoadFile(dirPath) — e.g. SDK code that always assumes a .tgz, glob results that matched a directory, or user-supplied --chart paths that point at an unpacked chart directory.
Common situations: CLI flags accepting either a tgz or a directory and the code hardcoding LoadFile; a download step that should have produced a file but left an extracted directory; testing against local unpacked charts.
Related errors
- cannot load a directory
- chart file %q is larger than the maximum file size %d
- error reading %s: %w
- unable to detect chart version, no Chart.yaml found
- Chart.yaml file is missing
AI-assisted analysis of helm/helm@2a29f1770b (2026-08-15).
Data as JSON: /api/errors/b4c34ac165176568.
Report an issue: GitHub.