{"record":{"id":"b4c34ac165176568","repo":"helm/helm","slug":"cannot-load-a-directory-b4c34a","errorCode":null,"errorMessage":"cannot load a directory","messagePattern":"cannot load a directory","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/chart/v2/loader/archive.go","lineNumber":43,"sourceCode":"\n\t\"helm.sh/helm/v4/pkg/chart/loader/archive\"\n\tchart \"helm.sh/helm/v4/pkg/chart/v2\"\n)\n\n// FileLoader loads a chart from a file\ntype FileLoader string\n\n// Load loads a chart\nfunc (l FileLoader) Load() (*chart.Chart, error) {\n\treturn LoadFile(string(l))\n}\n\n// LoadFile loads from an archive file.\nfunc LoadFile(name string) (*chart.Chart, error) {\n\tif fi, err := os.Stat(name); err != nil {\n\t\treturn nil, err\n\t} else if fi.IsDir() {\n\t\treturn nil, errors.New(\"cannot load a directory\")\n\t}\n\n\traw, err := os.Open(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer raw.Close()\n\n\terr = archive.EnsureArchive(name, raw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc, err := LoadArchive(raw)\n\tif err != nil {\n\t\tif errors.Is(err, gzip.ErrHeader) {\n\t\t\treturn nil, fmt.Errorf(\"file '%s' does not appear to be a valid chart file (details: %w)\", name, err)\n\t\t}","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/helm/helm/blob/2a29f1770b62844b27197d2507377361d45ad7c0/pkg/chart/v2/loader/archive.go#L25-L61","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nfunc loadChart(p string) (*chart.Chart, error) {\n    return c2loader.LoadFile(p)\n}\n\n// after\nfunc loadChart(p string) (*chart.Chart, error) {\n    l, err := c2loader.Loader(p)\n    if err != nil {\n        return nil, err\n    }\n    return l.Load()\n}","handlingStrategy":"validation","validationCode":"// Validate the path type before choosing the loader\nfunc isRegularFile(p string) (bool, error) {\n    fi, err := os.Stat(p)\n    if err != nil {\n        return false, err\n    }\n    return !fi.IsDir(), nil\n}","typeGuard":null,"tryCatchPattern":"l, err := c2loader.Loader(path) // dispatches DirLoader vs FileLoader via os.Stat\nif err != nil {\n    return nil, err\n}\nc, err := l.Load()\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot load a directory\") {\n        return nil, fmt.Errorf(\"%s is a directory — use LoadDir\", path)\n    }\n    return nil, err\n}","preventionTips":["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"],"tags":["helm","chart","loader","sdk","filesystem"],"backgroundTag":null,"analyzedSha":"2a29f1770b62844b27197d2507377361d45ad7c0","analyzedAt":"2026-08-15T22:02:47.490Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}