{"record":{"id":"6126772f20cf2df0","repo":"helm/helm","slug":"failed-to-extract-archive-w","errorCode":null,"errorMessage":"failed to extract archive: %w","messagePattern":"failed to extract archive: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/plugin/installer/local_installer.go","lineNumber":146,"sourceCode":"\tprovSource := i.Source + \".prov\"\n\tif provData, err := os.ReadFile(provSource); err == nil {\n\t\tprovPath := tarballPath + \".prov\"\n\t\tif err := os.WriteFile(provPath, provData, 0o644); err != nil {\n\t\t\tslog.Debug(\"failed to save provenance file\", \"error\", err)\n\t\t}\n\t}\n\n\t// Create a temporary directory for extraction\n\ttempDir, err := os.MkdirTemp(\"\", \"helm-plugin-extract-\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temp directory: %w\", err)\n\t}\n\tdefer os.RemoveAll(tempDir)\n\n\t// Extract the archive\n\tbuffer := bytes.NewBuffer(data)\n\tif err := i.extractor.Extract(buffer, tempDir); err != nil {\n\t\treturn fmt.Errorf(\"failed to extract archive: %w\", err)\n\t}\n\n\t// Plugin directory should be named after the plugin at the archive root\n\tpluginName := stripPluginName(filepath.Base(i.Source))\n\tpluginDir := filepath.Join(tempDir, pluginName)\n\tif _, err = os.Stat(filepath.Join(pluginDir, \"plugin.yaml\")); err != nil {\n\t\treturn fmt.Errorf(\"plugin.yaml not found in expected directory %s: %w\", pluginDir, err)\n\t}\n\n\t// Copy to the final destination\n\tslog.Debug(\"copying\", \"source\", pluginDir, \"path\", i.Path())\n\treturn fs.CopyDir(pluginDir, i.Path())\n}\n\n// Update updates a local repository\nfunc (i *LocalInstaller) Update() error {\n\tslog.Debug(\"local repository is auto-updated\")\n\treturn nil","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/helm/helm/blob/2a29f1770b62844b27197d2507377361d45ad7c0/internal/plugin/installer/local_installer.go#L128-L164","documentation":"TarGzExtractor.Extract failed while unpacking the local tarball into the temp dir. Distinct inner causes: gzip.NewReader error (file is not gzip — e.g. a zip renamed to .tgz), tar stream error mid-read (truncation), cleanJoin rejecting an entry name ('..', ':', absolute path), an entry typeflag outside TypeDir/TypeReg (symlinks and hardlinks hit the 'unknown type' branch and are rejected), or target-file creation failures (permissions, ENOSPC).","triggerScenarios":"helm plugin install ./myplugin-1.0.0.tgz where the archive was created on macOS with symlinks (tar preserves them as TypeSymlink entries, unsupported here); archive contains ./ or absolute entries; truncated file; read-only TMPDIR.","commonSituations":"macOS/Linux packaging differences (symlinked binaries inside plugin dirs); files zipped then renamed; incomplete scp/ftp transfers.","solutions":["Inspect entries: tar -tvf myplugin-1.0.0.tgz — look for 'l' (symlink) or 'h' (hardlink) types and for names starting with / or containing ..","Repackage with regular files only and relative paths: cd build && tar -czf ../myplugin-1.0.0.tgz myplugin/","Confirm the file is genuinely gzip: file myplugin-1.0.0.tgz","Ensure TMPDIR is writable and has space"],"exampleFix":"# before: macOS tar keeps symlink\nln -s ../shared/binary myplugin/bin && tar -czf myplugin-1.0.0.tgz myplugin\n# after: real file, relative paths\ncp ../shared/binary myplugin/bin && tar -czf myplugin-1.0.0.tgz myplugin","handlingStrategy":"validation","validationCode":"// Reject archives that TarGzExtractor cannot handle before installing: only dirs and regular files, safe relative names.\nfunc extractionSafeTgz(p string) error {\n\tf, _ := os.Open(p)\n\tdefer f.Close()\n\tgz, err := gzip.NewReader(f)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"not gzip: %w\", err)\n\t}\n\ttr := tar.NewReader(gz)\n\tfor {\n\t\th, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif h.Typeflag != tar.TypeDir && h.Typeflag != tar.TypeReg && h.Typeflag != tar.TypeXHeader && h.Typeflag != tar.TypeXGlobalHeader {\n\t\t\treturn fmt.Errorf(\"entry %s has unsupported type %b (symlinks/hardlinks not supported)\", h.Name, h.Typeflag)\n\t\t}\n\t\tif path.IsAbs(h.Name) || strings.Contains(h.Name, \":\") || strings.Contains(filepath.ToSlash(h.Name), \"..\") {\n\t\t\treturn fmt.Errorf(\"entry %s has an unsafe name\", h.Name)\n\t\t}\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Package plugin tarballs without symlinks or hardlinks — copy real files","Create tarballs from inside the build root so all entry names are relative","Run tar -tvf on new plugin packages as a CI gate"],"tags":["go","helm","plugin","archive","tar","extraction","security"],"backgroundTag":null,"analyzedSha":"2a29f1770b62844b27197d2507377361d45ad7c0","analyzedAt":"2026-08-15T22:02:47.490Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}