{"record":{"id":"50abe50f56cff6fa","repo":"hasura/graphql-engine","slug":"failed-to-link-installed-plugin-w","errorCode":null,"errorMessage":"failed to link installed plugin: %w","messagePattern":"failed to link installed plugin: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/plugins.go","lineNumber":354,"sourceCode":"\tif _, ok := IsSubPath(subPathAbs, pathAbs); !ok {\n\t\tif err != nil {\n\t\t\treturn errors.E(\n\t\t\t\top,\n\t\t\t\tfmt.Errorf(\n\t\t\t\t\t\"the fullPath %q does not extend the sub-fullPath %q: %w\",\n\t\t\t\t\tfullPath,\n\t\t\t\t\tinstallDir,\n\t\t\t\t\terr,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\terr = createOrUpdateLink(binDir, fullPath, plugin.Name)\n\tif err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"failed to link installed plugin: %w\", err))\n\t}\n\n\treturn nil\n}\n\n// Upgrade will reinstall and delete the old plugin. The operation tries\n// to not get the plugin dir in a bad state if it fails during the process.\nfunc (c *Config) Upgrade(pluginName string, version *semver.Version) (Plugin, error) {\n\tvar op errors.Op = \"plugins.Config.Upgrade\"\n\n\tps, err := c.LoadPluginByName(pluginName)\n\tif err != nil {\n\t\tif stderrors.Is(err, fs.ErrNotExist) {\n\t\t\treturn Plugin{}, errors.E(\n\t\t\t\top,\n\t\t\t\tfmt.Errorf(\"plugin %q does not exist in the plugin index\", pluginName),\n\t\t\t)\n\t\t}","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/plugins.go#L336-L372","documentation":"installPlugin finishes by symlinking (or copying, on Windows) the installed plugin binary into the shared bin directory via createOrUpdateLink. This error means that final link step failed — typically because the bin directory cannot be created, the destination link is held open/locked, or a same-named file exists that is not the CLI's link.","triggerScenarios":"Config.Install or Config.Upgrade completing download/extract, then failing in createOrUpdateLink(binDir, fullPath, plugin.Name): nonexistent or non-writable bin dir, EPERM/EACCES on Windows or restricted filesystems, an existing non-symlink file at the link target, or antivirus locking the freshly extracted binary.","commonSituations":"Windows file locking or Defender scanning the new binary; a stale regular file (not symlink) named after the plugin in the bin dir; bin directory on a read-only or network mount; missing admin rights on system paths.","solutions":["Check the wrapped error — EACCES/EPERM points to permissions, EEXIST to a conflicting file","Remove any leftover regular file named <plugin>.exe/<plugin> in the configured bin directory and retry","Ensure the bin directory is writable (and on a filesystem supporting symlinks; on Windows enable Developer Mode or run elevated)","Temporarily exclude the bin dir from antivirus scanning if creation is blocked right after extraction"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"binDir := paths.BinPath()\nif err := os.MkdirAll(binDir, 0o755); err != nil { return err }\nif info, err := os.Stat(binDir); err != nil || !info.IsDir() { return fmt.Errorf(\"bin dir unusable\") }","typeGuard":null,"tryCatchPattern":"if err := plugins.Install(p, plat); err != nil {\n    if strings.Contains(err.Error(), \"failed to link installed plugin\") {\n        // clear stale non-symlink file at the link target, then retry once\n    }\n}","preventionTips":["Pre-create and keep the bin directory writable","On Windows enable symlink privileges (Developer Mode) or run elevated","Exclude the bin dir from antivirus real-time scanning"],"tags":["symlink","plugin-install","filesystem","permissions","windows"],"backgroundTag":"symlink-creation-failed","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}