{"record":{"id":"b3d7a8152e013b79","repo":"router-for-me/CLIProxyAPI","slug":"parse-redirect-location-w","errorCode":null,"errorMessage":"parse redirect location: %w","messagePattern":"parse redirect location: %w","errorType":"http","errorClass":null,"httpStatus":502,"severity":"warning","filePath":"internal/pluginstore/github.go","lineNumber":254,"sourceCode":"\tcase http.StatusMovedPermanently, http.StatusFound, http.StatusSeeOther, http.StatusTemporaryRedirect, http.StatusPermanentRedirect:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc pluginStoreRedirectURL(resp *http.Response, requestURL string) (string, error) {\n\tlocation := strings.TrimSpace(resp.Header.Get(\"Location\"))\n\tif location == \"\" {\n\t\treturn \"\", fmt.Errorf(\"redirect missing Location header\")\n\t}\n\tbase, errBase := url.Parse(requestURL)\n\tif errBase != nil {\n\t\treturn \"\", fmt.Errorf(\"parse redirect base: %w\", errBase)\n\t}\n\tnext, errNext := base.Parse(location)\n\tif errNext != nil {\n\t\treturn \"\", fmt.Errorf(\"parse redirect location: %w\", errNext)\n\t}\n\tif next.Scheme == \"\" || next.Host == \"\" {\n\t\treturn \"\", fmt.Errorf(\"redirect location is not absolute\")\n\t}\n\treturn next.String(), nil\n}\n\nfunc readPluginStoreResponse(resp *http.Response, maxSize int64, authenticated bool) ([]byte, error) {\n\tdefer func() {\n\t\tif errClose := resp.Body.Close(); errClose != nil {\n\t\t\tlog.WithError(errClose).Debug(\"failed to close plugin store response body\")\n\t\t}\n\t}()\n\tif resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {\n\t\tif authenticated {\n\t\t\treturn nil, fmt.Errorf(\"unexpected status %d\", resp.StatusCode)\n\t\t}\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/github.go#L236-L272","documentation":"After parsing the base, pluginStoreRedirectURL resolves the Location value against it with base.Parse(location). 'parse redirect location: %w' wraps that failure — the Location header value itself is not parseable as a URI reference (for example it contains control characters or an invalid escape sequence).","triggerScenarios":"A Location header with malformed percent-encodings (e.g. '%zz') or embedded control characters/CR-LF, causing url.URL reference resolution to fail.","commonSituations":"Buggy servers or middleboxes emitting unescaped characters in Location; crafted or corrupted responses; rarely, GitHub API edge cases after token-redemption redirects.","solutions":["Capture the raw Location header (curl -I) and fix the encoding on the server that emits it.","Percent-encode dynamic path segments in redirect targets if you control the redirecting service.","Pin direct artifact URLs in the manifest to avoid the broken redirector altogether."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := fetch(); err != nil {\n    if strings.Contains(err.Error(), \"parse redirect location\") {\n        // malformed Location from server — pin a direct URL; do not retry the same hop\n    }\n}","preventionTips":["Percent-encode redirect targets you control.","Pin direct artifact URLs to skip broken redirectors."],"tags":["http","redirects","url-validation","headers","plugin-store"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}