{"record":{"id":"36535b4211ffd63a","repo":"router-for-me/CLIProxyAPI","slug":"stat-target-plugin-w","errorCode":null,"errorMessage":"stat target plugin: %w","messagePattern":"stat target plugin: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/install.go","lineNumber":272,"sourceCode":"\treader, errZip := zip.NewReader(bytes.NewReader(archiveData), int64(len(archiveData)))\n\tif errZip != nil {\n\t\treturn InstallResult{}, fmt.Errorf(\"open zip: %w\", errZip)\n\t}\n\n\tlibraryData, mode, errLibrary := readTargetLibrary(reader, id, version, options.GOOS)\n\tif errLibrary != nil {\n\t\treturn InstallResult{}, errLibrary\n\t}\n\n\ttargetPath, errTarget := installTargetPath(options, id, version)\n\tif errTarget != nil {\n\t\treturn InstallResult{}, errTarget\n\t}\n\toverwritten := false\n\tif _, errStat := os.Stat(targetPath); errStat == nil {\n\t\toverwritten = true\n\t} else if !errors.Is(errStat, os.ErrNotExist) {\n\t\treturn InstallResult{}, fmt.Errorf(\"stat target plugin: %w\", errStat)\n\t}\n\tif overwritten {\n\t\texistingData, errReadExisting := os.ReadFile(targetPath)\n\t\tif errReadExisting != nil {\n\t\t\treturn InstallResult{}, fmt.Errorf(\"read target plugin: %w\", errReadExisting)\n\t\t}\n\t\tif bytes.Equal(existingData, libraryData) {\n\t\t\treturn InstallResult{\n\t\t\t\tID:          id,\n\t\t\t\tVersion:     strings.TrimSpace(plugin.Version),\n\t\t\t\tPath:        targetPath,\n\t\t\t\tOverwritten: true,\n\t\t\t\tSkipped:     true,\n\t\t\t}, nil\n\t\t}\n\t}\n\t// Re-check immediately before replacing an existing file: the same version\n\t// may have been loaded while the archive was being downloaded and verified.","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/install.go#L254-L290","documentation":"Wrapped error from InstallArchive when os.Stat on the computed target path fails with anything other than os.ErrNotExist — i.e. the existence check itself is broken, typically a permission problem on a parent directory or a path component that is not a directory. Only a clean 'does not exist' is treated as 'will create'; ambiguous stat failures abort the install rather than risk overwriting blindly.","triggerScenarios":"options.PluginsDir points into a directory without execute/search permission for the process user, or a non-directory file sits where a directory component is expected (e.g. 'plugins' is a regular file), producing EACCES/ENOTDIR/ELOOP from Stat.","commonSituations":"Running the installer as a different user than the one that owns the plugins directory; containers with read-only or mismounted volumes; a previous install created a file where a directory path now expects one; overly strict umask or SELinux/AppArmor denials.","solutions":["Check the underlying stat error (errors.Is(errStat, fs.ErrPermission) etc.) to identify the exact directory in the path that denies access","Ensure options.PluginsDir and its GOOS/GOARCH subdirectories exist and are writable/searchable by the process user","Remove or relocate any regular file occupying a needed directory component"],"exampleFix":"# before: plugins dir owned by root, process runs as app-user\nls -ld /opt/app/plugins # drwx------ root root\n\n# after\nmkdir -p /opt/app/plugins/linux/amd64 && chown -R app-user:app-user /opt/app/plugins","handlingStrategy":"try-catch","validationCode":"func targetDirWritable(pluginsDir, goos, goarch string) error {\n    dir := filepath.Join(pluginsDir, goos, goarch)\n    info, err := os.Stat(dir)\n    if err == nil && !info.IsDir() {\n        return fmt.Errorf(\"%s exists but is not a directory\", dir)\n    }\n    if err != nil {\n        if err := os.MkdirAll(dir, 0o755); err != nil {\n            return fmt.Errorf(\"cannot create %s: %w\", dir, err)\n        }\n        return nil\n    }\n    probe := filepath.Join(dir, \".write-probe\")\n    if err := os.WriteFile(probe, nil, 0o644); err != nil {\n        return fmt.Errorf(\"%s not writable: %w\", dir, err)\n    }\n    _ = os.Remove(probe)\n    return nil\n}","typeGuard":"func isPermissionErr(err error) bool {\n    return errors.Is(err, fs.ErrPermission) || strings.Contains(err.Error(), \"stat target plugin:\") && errors.Is(errors.Unwrap(err), fs.ErrPermission)\n}","tryCatchPattern":"if _, err := pluginstore.InstallArchive(data, plugin, options); err != nil {\n    if strings.Contains(err.Error(), \"stat target plugin:\") {\n        if errors.Is(err, fs.ErrPermission) {\n            // fix ownership/permissions of PluginsDir tree, then retry\n        } else if errors.Is(err, syscall.ENOTDIR) {\n            // a file occupies a directory component; remove or relocate it\n        }\n    }\n}","preventionTips":["Create and chown the PluginsDir/<goos>/<goarch> tree at deploy time","Run all installs as one dedicated user owning the plugins directory","Write-probe the target directory before starting installs"],"tags":["go","plugin-store","filesystem","permissions","install"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}