{"record":{"id":"b30bb822f2cf983c","repo":"asdf-vm/asdf","slug":"unable-to-update-plugin-index-w","errorCode":null,"errorMessage":"unable to update plugin index: %w","messagePattern":"unable to update plugin index: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginindex/pluginindex.go","lineNumber":109,"sourceCode":"\t\treturn p.doUpdate()\n\t}\n\n\t// Convert minutes to nanoseconds\n\tupdateDurationNs := int64(p.updateDurationMinutes) * (6e10)\n\n\tif updated > updateDurationNs && !p.disableUpdate {\n\t\treturn p.doUpdate()\n\t}\n\n\treturn false, nil\n}\n\nfunc (p PluginIndex) doUpdate() (bool, error) {\n\t// pass in empty string as we want the repo to figure out what the latest\n\t// commit is\n\t_, _, _, err := p.repo.Update(\"\")\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"unable to update plugin index: %w\", err)\n\t}\n\n\t// Touch update file\n\treturn touchFS(p.directory)\n}\n\n// GetPluginSourceURL looks up a plugin by name and returns the repository URL\n// for easy install by the user.\nfunc (p PluginIndex) GetPluginSourceURL(name string) (string, error) {\n\t_, err := p.Refresh()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\turl, err := readPlugin(p.directory, name)\n\tif err != nil {\n\t\treturn \"\", err\n\t}","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/asdf-vm/asdf/blob/074a1722ca88d6677f228541ce06efaf4f9924d4/internal/pluginindex/pluginindex.go#L91-L127","documentation":"doUpdate refreshes an existing plugin index repository with p.repo.Update(\"\") (fetch to latest commit). If the git update fails, the error is wrapped as 'unable to update plugin index'. This path only runs when the index already exists but is older than the staleness threshold.","triggerScenarios":"Refresh (via Get/GetPluginSourceURL) when the index repo exists and the update-timestamp is stale, and: the network is down; the remote rejected the fetch (auth, rate limit); the local clone has diverged or is corrupt; git is unavailable.","commonSituations":"Intermittent network drops; GitHub outages or rate limiting; local index repo left in a dirty/broken state by a killed process; VPN disconnected.","solutions":["Check network access to the index remote and retry — updates are transient failures.","Delete the index directory (default ~/.asdf/repository or repo/ under the index dir) and let Refresh re-clone it.","Fix the local clone manually (git -C <dir> fetch && git reset --hard origin).","Verify git/proxy configuration if behind a firewall."],"exampleFix":"// before: corrupt/stale index repo\n// after: re-clone from scratch\nrm -rf \"${ASDF_DATA_DIR:-$HOME/.asdf}/repository\"\nasdf plugin list all   # triggers fresh clone","handlingStrategy":"fallback","validationCode":"if fi, err := os.Stat(filepath.Join(indexDir, \".git\")); err != nil || !fi.IsDir() {\n    // repo missing/corrupt — remove so Refresh re-clones\n    os.RemoveAll(indexDir)\n}","typeGuard":null,"tryCatchPattern":"ok, err := idx.Refresh()\nif err != nil && strings.Contains(err.Error(), \"unable to update plugin index\") {\n    os.RemoveAll(indexDir)      // nuke broken clone\n    ok, err = idx.Refresh()     // fresh clone fallback\n}","preventionTips":["On repeated update failures, delete the index repo dir to force a clean re-clone.","Check GitHub status / rate limits before assuming local breakage.","Avoid killing asdf mid-update; interruptions can corrupt the clone.","Retry transient network failures before manual intervention."],"tags":["git","network","plugin-index"],"backgroundTag":"git-fetch-failed","analyzedSha":"074a1722ca88d6677f228541ce06efaf4f9924d4","analyzedAt":"2026-08-30T19:56:42.972Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}