{"record":{"id":"c45bd26b41138172","repo":"chenhg5/cc-connect","slug":"unexpected-redirect-s","errorCode":null,"errorMessage":"unexpected redirect: %s","messagePattern":"unexpected redirect: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/cc-connect/update.go","lineNumber":282,"sourceCode":"\tnoRedirect := &http.Client{\n\t\tTimeout: 15 * time.Second,\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\treturn http.ErrUseLastResponse\n\t\t},\n\t}\n\tresp2, err := noRedirect.Get(latestURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"request failed: %w\", err)\n\t}\n\tdefer resp2.Body.Close()\n\n\tloc := resp2.Header.Get(\"Location\")\n\tif loc == \"\" {\n\t\treturn nil, fmt.Errorf(\"no release found\")\n\t}\n\tparts := strings.Split(loc, \"/tag/\")\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"unexpected redirect: %s\", loc)\n\t}\n\treturn &githubRelease{TagName: parts[1], HTMLURL: loc}, nil\n}\n\nfunc binaryAssetName(tag string) string {\n\tgoos := runtime.GOOS\n\tgoarch := runtime.GOARCH\n\tname := fmt.Sprintf(\"cc-connect-%s-%s-%s\", tag, goos, goarch)\n\tif goos == \"windows\" {\n\t\tname += \".exe\"\n\t}\n\treturn name\n}\n\nfunc archiveAssetName(tag string) string {\n\tgoos := runtime.GOOS\n\tgoarch := runtime.GOARCH\n\tbase := fmt.Sprintf(\"cc-connect-%s-%s-%s\", tag, goos, goarch)","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/update.go#L264-L300","documentation":"fetchLatestStableRelease parses the redirect Location URL by splitting on \"/tag/\" and expects exactly two parts. This error means the Location header was present but its format didn't match the expected https://github.com/<owner>/<repo>/releases/tag/<tag> shape, so the tag cannot be extracted.","triggerScenarios":"strings.Split(loc, \"/tag/\") returns != 2 parts: Location points somewhere unexpected — a login/SSO redirect, an error page, a proxy URL, or a changed releases URL layout.","commonSituations":"An SSO/identity provider redirect intercepting the request; a misconfigured internal proxy rewriting Location; repo moved/renamed causing a redirect chain to a different URL format; future GitHub URL scheme change.","solutions":["Inspect the actual Location value embedded in the message to see what GitHub returned","Bypass any SSO/proxy that rewrites redirects to github.com","Parse the tag with net/url path parsing instead of naive string splitting to tolerate URL variations","Fall back to the JSON /releases endpoint, whose tag_name field is stable"],"exampleFix":"// before\nparts := strings.Split(loc, \"/tag/\")\nif len(parts) != 2 {\n    return nil, fmt.Errorf(\"unexpected redirect: %s\", loc)\n}\n// after\nu, err := url.Parse(loc)\nif err != nil {\n    return nil, fmt.Errorf(\"unexpected redirect: %s\", loc)\n}\nsegs := strings.Split(strings.TrimRight(u.Path, \"/\"), \"/\")\nif len(segs) < 2 || segs[len(segs)-2] != \"tag\" {\n    return nil, fmt.Errorf(\"unexpected redirect: %s\", loc)\n}\ntag := segs[len(segs)-1]","handlingStrategy":"type-guard","validationCode":"// sanity-check the Location URL shape before trusting it:\nloc := resp.Header.Get(\"Location\")\nu, err := url.Parse(loc)\nif err != nil || u.Host != \"github.com\" || !strings.Contains(u.Path, \"/releases/tag/\") {\n    return errors.New(\"redirect does not look like a release URL: \" + loc)\n}","typeGuard":"// Go: narrowing helper for a valid release-redirect URL\nfunc isReleaseRedirect(loc string) (tag string, ok bool) {\n    u, err := url.Parse(loc)\n    if err != nil || u.Host != \"github.com\" { return \"\", false }\n    parts := strings.Split(strings.Trim(u.Path, \"/\"), \"/\")\n    if len(parts) < 5 || parts[len(parts)-2] != \"tag\" { return \"\", false }\n    return parts[len(parts)-1], true\n}","tryCatchPattern":"// Go: validate the parsed tag before proceeding\ntag, ok := isReleaseRedirect(loc)\nif !ok {\n    return nil, fmt.Errorf(\"unexpected redirect: %s\", loc) // log loc verbatim for triage\n}","preventionTips":["Parse URLs with net/url instead of fragile string splitting","Expect SSO/IDP redirects in corporate environments and bypass them for github.com","Log the full Location header whenever parsing fails","Add an integration test that asserts the current GitHub releases URL layout"],"tags":["http","redirect","url-parsing","github-api","update-checker"],"backgroundTag":"unexpected-response-shape","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}