{"record":{"id":"13f049965509ec9c","repo":"hasura/graphql-engine","slug":"failed-to-read-the-symlink-in-q-w","errorCode":null,"errorMessage":"failed to read the symlink in %q: %w","messagePattern":"failed to read the symlink in %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/util.go","lineNumber":236,"sourceCode":"\t\t\treturn errors.E(\n\t\t\t\top,\n\t\t\t\tfmt.Errorf(\"failed to create a symlink from %q to %q: %w\", binary, dst, err),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// removeLink removes a symlink reference if exists.\nfunc removeLink(path string) error {\n\tvar op errors.Op = \"plugins.removeLink\"\n\n\tfi, err := os.Lstat(path)\n\tif stderrors.Is(err, fs.ErrNotExist) {\n\t\treturn nil\n\t} else if err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"failed to read the symlink in %q: %w\", path, err))\n\t}\n\n\tif fi.Mode()&os.ModeSymlink == 0 && !IsWindows() {\n\t\treturn errors.E(op, fmt.Errorf(\"file %q is not a symlink (mode=%s)\", path, fi.Mode()))\n\t}\n\n\tif err := os.Remove(path); err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"failed to remove the symlink in %q: %w\", path, err))\n\t}\n\n\treturn nil\n}\n\n// PluginNameToBin creates the name of the symlink file for the plugin name.\n// It converts dashes to underscores.\nfunc PluginNameToBin(name string, isWindows bool) string {\n\tname = strings.ReplaceAll(name, \"-\", \"_\")\n","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/util.go#L218-L254","documentation":"Thrown when os.Lstat fails for a path that should be a plugin symlink during uninstall/relink, and the error is anything other than 'file does not exist' (which is treated as success). The wrapped error typically indicates permission problems on the parent directory or an I/O failure reading the file's metadata.","triggerScenarios":"Calling Uninstall or createOrUpdateLink when os.Lstat on the symlink path returns a non-ErrNotExist error: permission denied on the containing directory, a path component that is not a directory, or a filesystem/IO error.","commonSituations":"The plugins bin directory or an ancestor was made read-only, the directory was replaced by a Docker bind mount with odd permissions, or an antivirus/locking mechanism on Windows interferes with stat calls.","solutions":["Check permissions on the full path: namei -l ~/.hasura/plugins/bin/<plugin> and fix with chmod/chown.","Verify no path component is a file rather than a directory; recreate the bin directory if corrupted.","Temporarily disable antivirus/lockers on Windows and retry uninstall.","As a last resort, manually delete the plugins bin directory and let the CLI recreate it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// verify the path is statable before uninstalling\nif _, err := os.Lstat(linkPath); err != nil && !errors.Is(err, fs.ErrNotExist) {\n    log.Fatalf(\"cannot stat %s: %v\", linkPath, err)\n}","typeGuard":null,"tryCatchPattern":"if err := plugins.Uninstall(...); err != nil {\n    if strings.Contains(err.Error(), \"failed to read the symlink\") {\n        // directory-level permission problem; fix and retry\n    }\n}","preventionTips":["Avoid running the CLI under sudo so the bin directory stays user-owned.","Keep the plugins directory on a local filesystem, not a restricted network mount."],"tags":["go","filesystem","lstat","permissions","plugin-uninstall"],"backgroundTag":"file-stat-permission-denied","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}