{"record":{"id":"90178e2a879dfa82","repo":"pulumi/pulumi","slug":"extracting-symlink-s-w","errorCode":null,"errorMessage":"extracting symlink %s: %w","messagePattern":"extracting symlink (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdk/go/common/util/archive/archive.go","lineNumber":131,"sourceCode":"\t\ttarget = filepath.Clean(target)\n\t\tif target != cleanDir && !strings.HasPrefix(target, cleanDir+string(os.PathSeparator)) {\n\t\t\treturn fmt.Errorf(\"symlink %s points outside the extraction directory\", header.Name)\n\t\t}\n\n\t\tlinkDir := filepath.Dir(path)\n\t\tif _, err := os.Stat(linkDir); err != nil {\n\t\t\tif err = os.MkdirAll(linkDir, 0o0700); err != nil {\n\t\t\t\treturn fmt.Errorf(\"extracting dir %s: %w\", linkDir, err)\n\t\t\t}\n\t\t}\n\n\t\tif _, err := os.Lstat(path); err == nil {\n\t\t\tif err = os.Remove(path); err != nil {\n\t\t\t\treturn fmt.Errorf(\"removing existing file %s before creating symlink: %w\", path, err)\n\t\t\t}\n\t\t}\n\t\tif err := os.Symlink(header.Linkname, path); err != nil {\n\t\t\treturn fmt.Errorf(\"extracting symlink %s: %w\", path, err)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unexpected plugin file type %s (%v)\", header.Name, header.Typeflag)\n\t}\n\n\treturn nil\n}\n\n// ExtractTGZ uncompresses a .tar.gz/.tgz file into a specific directory.\nfunc ExtractTGZ(r io.Reader, dir string) error {\n\t// Convert to absolute path so that path traversal checks in extractFile are reliable.\n\tabsDir, err := filepath.Abs(dir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"resolving destination path: %w\", err)\n\t}\n\n\tgzr, err := gzip.NewReader(r)\n\tif err != nil {","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/go/common/util/archive/archive.go#L113-L149","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n# extracting onto /media/usb (FAT32) -> symlink not supported\n// after\n# set PULUMI_HOME to an ext4/NTFS path\nexport PULUMI_HOME=/home/user/.pulumi","handlingStrategy":"validation","validationCode":"tmp, err := os.MkdirTemp(\"\", \"pulumitest\")\nif err == nil {\n\tdefer os.RemoveAll(tmp)\n\tif err := os.Symlink(\"target\", filepath.Join(tmp, \"probe\")); err != nil {\n\t\treturn fmt.Errorf(\"filesystem does not support symlinks: %w\", err)\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := extractFile(r, header, dir); err != nil {\n\tif strings.Contains(err.Error(), \"extracting symlink\") {\n\t\treturn fmt.Errorf(\"cannot create symlink at %s (unsupported fs or missing privilege); set PULUMI_HOME to a symlink-capable volume\", dir)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["go","archive","symlink","filesystem"],"backgroundTag":"symlink-creation-failed","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}