pulumi/pulumi · error
extracting symlink %s: %w
Error message
extracting symlink %s: %w
What it means
Wraps an os.Symlink failure after the destination path was verified clear. The kernel refused to create the symlink at `path` pointing to header.Linkname.
Source
Thrown at sdk/go/common/util/archive/archive.go:131
target = filepath.Clean(target)
if target != cleanDir && !strings.HasPrefix(target, cleanDir+string(os.PathSeparator)) {
return fmt.Errorf("symlink %s points outside the extraction directory", header.Name)
}
linkDir := filepath.Dir(path)
if _, err := os.Stat(linkDir); err != nil {
if err = os.MkdirAll(linkDir, 0o0700); err != nil {
return fmt.Errorf("extracting dir %s: %w", linkDir, err)
}
}
if _, err := os.Lstat(path); err == nil {
if err = os.Remove(path); err != nil {
return fmt.Errorf("removing existing file %s before creating symlink: %w", path, err)
}
}
if err := os.Symlink(header.Linkname, path); err != nil {
return fmt.Errorf("extracting symlink %s: %w", path, err)
}
default:
return fmt.Errorf("unexpected plugin file type %s (%v)", header.Name, header.Typeflag)
}
return nil
}
// ExtractTGZ uncompresses a .tar.gz/.tgz file into a specific directory.
func ExtractTGZ(r io.Reader, dir string) error {
// Convert to absolute path so that path traversal checks in extractFile are reliable.
absDir, err := filepath.Abs(dir)
if err != nil {
return fmt.Errorf("resolving destination path: %w", err)
}
gzr, err := gzip.NewReader(r)
if err != nil {View on GitHub (pinned to 793f7b2e16)
Solutions
- Extract into a filesystem that supports symlinks (NTFS/ext4, not FAT/exFAT)
- On Windows, enable Developer Mode or run with symlink privilege (SeCreateSymbolicLinkPrivilege)
- Ensure no concurrent process is extracting the same plugin; clear the plugin dir and retry
- Check write permissions on the destination directory
Example fix
// before # extracting onto /media/usb (FAT32) -> symlink not supported // after # set PULUMI_HOME to an ext4/NTFS path export PULUMI_HOME=/home/user/.pulumi
Defensive patterns
Strategy: validation
Validate before calling
tmp, err := os.MkdirTemp("", "pulumitest")
if err == nil {
defer os.RemoveAll(tmp)
if err := os.Symlink("target", filepath.Join(tmp, "probe")); err != nil {
return fmt.Errorf("filesystem does not support symlinks: %w", err)
}
} Try / catch
if err := extractFile(r, header, dir); err != nil {
if strings.Contains(err.Error(), "extracting symlink") {
return fmt.Errorf("cannot create symlink at %s (unsupported fs or missing privilege); set PULUMI_HOME to a symlink-capable volume", dir)
}
return err
} Prevention
- Point PULUMI_HOME at a filesystem that supports symlinks (ext4, NTFS)
- On Windows, enable Developer Mode or grant symlink privilege
- Avoid concurrent extractions into the same plugin directory
When it happens
Trigger: Extracting a tar.TypeSymlink where os.Symlink fails: path already exists (EEXIST race), filesystem doesn't support symlinks (e.g. FAT/exFAT mounts, some Windows configs without privileges), or permission denied in the parent directory.
Common situations: Extracting plugin archives on filesystems without symlink support (Windows FAT32 USB, network shares, Docker volumes on some setups); concurrent installs racing on the same path.
Related errors
- removing existing file %s before creating symlink: %w
- resolving shell cwd: %w
- extracting dir %s: %w
- opening file %s for extraction: %w
- symlink %s points outside the extraction directory
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/90178e2a879dfa82.
Report an issue: GitHub.