helm/helm · error
failed to save tarball: %w
Error message
failed to save tarball: %w
What it means
After extracting metadata, LocalInstaller writes the original tarball bytes to <HELM_DATA_HOME>/plugins/<name>-<version>.tgz so future --verify runs have the exact artifact; os.WriteFile on that path failed. Causes: the plugins data directory is not writable, a leftover directory (not file) already exists at that exact filename, or the filesystem is full.
Source
Thrown at internal/plugin/installer/local_installer.go:124
// Read the archive file
data, err := os.ReadFile(i.Source)
if err != nil {
return fmt.Errorf("failed to read archive: %w", err)
}
// Copy the original tarball to plugins directory for verification
// Extract metadata to get the actual plugin name and version
metadata, err := plugin.ExtractTgzPluginMetadata(bytes.NewReader(data))
if err != nil {
return fmt.Errorf("failed to extract plugin metadata from tarball: %w", err)
}
filename := fmt.Sprintf("%s-%s.tgz", metadata.Name, metadata.Version)
tarballPath := helmpath.DataPath("plugins", filename)
if err := os.MkdirAll(filepath.Dir(tarballPath), 0o755); err != nil {
return fmt.Errorf("failed to create plugins directory: %w", err)
}
if err := os.WriteFile(tarballPath, data, 0o644); err != nil {
return fmt.Errorf("failed to save tarball: %w", err)
}
// Check for and copy .prov file if it exists
provSource := i.Source + ".prov"
if provData, err := os.ReadFile(provSource); err == nil {
provPath := tarballPath + ".prov"
if err := os.WriteFile(provPath, provData, 0o644); err != nil {
slog.Debug("failed to save provenance file", "error", err)
}
}
// Create a temporary directory for extraction
tempDir, err := os.MkdirTemp("", "helm-plugin-extract-")
if err != nil {
return fmt.Errorf("failed to create temp directory: %w", err)
}
defer os.RemoveAll(tempDir)
View on GitHub (pinned to 2a29f1770b)
Solutions
- Check the target: ls -la $(helm env HELM_DATA_HOME)/plugins/myplugin-1.0.0.tgz — if it is a directory, remove it
- Fix ownership of the plugins data dir: chown -R $(id -u):$(id -g) <data>/plugins or avoid mixing sudo and non-sudo Helm
- Free disk space if the volume is full (df -h)
- Retry the install after cleaning the colliding entry
Example fix
# before: leftover directory blocks the tarball path ls -d ~/.local/share/helm/plugins/myplugin-1.0.0.tgz/ # it's a dir # after: remove collision, reinstall rm -rf ~/.local/share/helm/plugins/myplugin-1.0.0.tgz && helm plugin install ./myplugin-1.0.0.tgz
Defensive patterns
Strategy: validation
Validate before calling
func tarballSlotFree(name, version string) error {
target := helmpath.DataPath("plugins", fmt.Sprintf("%s-%s.tgz", name, version))
if fi, err := os.Lstat(target); err == nil && fi.IsDir() {
return fmt.Errorf("a directory occupies %s — remove it first", target)
}
return nil
} Prevention
- After manual plugin removals, also clean <data>/plugins/<name>-<version>.tgz to avoid collisions
- Keep one owning user for the Helm data dir
- Monitor disk space on the data volume in CI
When it happens
Trigger: A previous partial install left a directory named myplugin-1.0.0.tgz in the plugins data dir; plugins dir owned by root after running Helm under sudo; ENOSPC; two different plugins colliding on the same name-version filename.
Common situations: Switching between sudo helm and plain helm (root-owned state); CI runners with tiny disks; uninstalling a plugin manually (rm -rf of the dir but not the saved tarball) leaving inconsistent state.
Related errors
- failed to save tarball: %w
- failed to read archive: %w
- failed to create plugins directory: %w
- failed to read plugin file: %w
- failed to access provenance file %s: %w
AI-assisted analysis of helm/helm@2a29f1770b (2026-08-15).
Data as JSON: /api/errors/3224c9abb48e91f1.
Report an issue: GitHub.