{"record":{"id":"9a6967bc1b94cde6","repo":"coreybutler/nvm-windows","slug":"error-reading-response-body-v","errorCode":null,"errorMessage":"error: reading response body: %v","messagePattern":"error: reading response body: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/upgrade/upgrade.go","lineNumber":742,"sourceCode":"\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn []byte{}, fmt.Errorf(\"error: received status code %d\", resp.StatusCode)\n\t}\n\n\treturn io.ReadAll(resp.Body)\n}\n\nfunc checkForUpdate(url string) (*Update, error) {\n\tu := Update{Assets: []string{}, Warnings: []string{}, VersionWarnings: []string{}}\n\tr := Release{}\n\n\t// Make the HTTP GET request\n\tutility.DebugLogf(\"checking for updates at %s\", url)\n\tbody, err := get(url, false)\n\tif err != nil {\n\t\treturn &u, fmt.Errorf(\"error: reading response body: %v\", err)\n\t}\n\n\t// Parse JSON into the struct\n\tutility.DebugLogf(\"Received:\\n%s\", string(body))\n\terr = json.Unmarshal(body, &r)\n\tif err != nil {\n\t\treturn &u, fmt.Errorf(\"error: parsing release: %v\", err)\n\t}\n\n\tu.Version = r.Version\n\tutility.DebugLogf(\"latest version: %s\", u.Version)\n\n\t// Comment the next line when development is complete\n\t// u.Version = \"2.0.0\"\n\tfor _, asset := range r.Assets {\n\t\tif value, exists := asset[\"name\"]; exists && value.(string) == \"update.exe\" {\n\t\t\tu.Assets = append(u.Assets, value.(string))\n\t\t}","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/coreybutler/nvm-windows/blob/5b18223ca19ff50d707f35410dbc6bd440a9f74d/src/upgrade/upgrade.go#L724-L760","documentation":"checkForUpdate fetches the latest-release JSON from the update URL and this error wraps any failure of that fetch. Despite the wording 'reading response body', the wrapped %v is the whole get() error — it can be a transport error (offline, DNS, TLS) or the non-200 status from error 48. The function still returns a usable (empty) Update struct alongside the error.","triggerScenarios":"Any 'nvm' invocation that triggers an update check while offline or behind a blocking proxy; update-check URL returning 403/429 (GitHub rate limit) so get() fails; DNS resolution failure for the update host; TLS interception with an untrusted root.","commonSituations":"Air-gapped or heavily proxied machines; GitHub API rate limits on shared CI egress IPs; flaky Wi-Fi at the moment the background update check fires; misconfigured mirror URL for the update feed.","solutions":["Confirm you can fetch the update-check URL directly (curl -L) from the same machine.","Address the underlying get() failure: proxy env vars, rate limit (wait), or TLS trust.","Set NVM_DISABLE_UPDATE_CHECK or equivalent offline behavior (per version docs) if the machine is intentionally offline.","Retry — the check runs on every command, so transient failures self-heal."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Wrap the update check so it degrades gracefully\nif _, err := checkForUpdate(url); err != nil {\n    utility.DebugLogf(\"update check skipped: %v\", err) // proceed without update info\n}","typeGuard":null,"tryCatchPattern":"The update check is auxiliary: catch, log at debug level, and continue normal nvm operation. Never let a failed check block node installs/uninstalls.","preventionTips":["Run the check lazily and at most once per interval.","Provide an offline/disable flag for air-gapped machines.","Keep the update URL pointed at the official endpoint."],"tags":["network","update-check","nvm-windows"],"backgroundTag":null,"analyzedSha":"5b18223ca19ff50d707f35410dbc6bd440a9f74d","analyzedAt":"2026-08-15T10:06:51.428Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}