larksuite/cli · error

official skills index redirected to non-HTTPS URL: %s

Error message

official skills index redirected to non-HTTPS URL: %s

What it means

FetchSkillsIndex fetches the official skills index over HTTP with a redirect check: the CheckRedirect hook rejects any redirect whose target URL is not HTTPS. This error is returned when the server (or a man-in-the-middle) redirects the request to a non-HTTPS URL, which the client treats as a security violation and aborts.

Source

Thrown at internal/selfupdate/updater.go:299

func (u *Updater) FetchSkillsIndex(source string) *NpmResult {
	if u.SkillsIndexFetchOverride != nil {
		return u.SkillsIndexFetchOverride()
	}

	r := &NpmResult{}
	ctx, cancel := context.WithTimeout(context.Background(), skillsIndexFetchTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, skillsIndexURL(source), nil)
	if err != nil {
		r.Err = err
		return r
	}

	client := transport.NewHTTPClient(0)
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if req.URL.Scheme != "https" {
			return fmt.Errorf("official skills index redirected to non-HTTPS URL: %s", req.URL.Redacted())
		}
		return nil
	}
	resp, err := client.Do(req)
	if err != nil {
		r.Err = err
		return r
	}
	defer resp.Body.Close()

	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		r.Err = fmt.Errorf("official skills index returned HTTP %d", resp.StatusCode)
		return r
	}

	limited := io.LimitReader(resp.Body, skillsIndexMaxBodySize+1)
	if _, err := io.Copy(&r.Stdout, limited); err != nil {
		r.Err = err

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Inspect the index URL/source being fetched and use a canonical HTTPS skills-index URL
  2. If you control the redirect, fix the server/mirror to redirect only to https:// URLs
  3. Bypass local proxies/captive portals that rewrite redirects to http and retry
  4. Verify you are not pointing at a stale mirror; reconfigure the skills source to the official HTTPS index

Example fix

// before
res := updater.FetchSkillsIndex("http://internal-mirror.example.com/index.json")
// after
res := updater.FetchSkillsIndex("https://internal-mirror.example.com/index.json")
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(indexURL)
if err != nil || u.Scheme != "https" { /* fix the source URL before fetching */ }

Type guard

func isHTTPS(s string) bool { u, err := url.Parse(s); return err == nil && u.Scheme == "https" }

Try / catch

res := updater.FetchSkillsIndex(source)
if res.Err != nil {
	if strings.Contains(res.Err.Error(), "redirected to non-HTTPS") {
		// reconfigure source to an HTTPS index URL
	} else {
		return res.Err
	}
}

Prevention

When it happens

Trigger: Calling Updater.FetchSkillsIndex(source) when the skills-index host responds with a 3xx redirect whose Location resolves to a URL with a scheme other than https (e.g. http://).

Common situations: Misconfigured internal mirror redirecting to plain HTTP; captive-portal or proxy rewriting redirects to http; typo'd or legacy index URL that redirects to a deprecated http endpoint; intentional downgrade attack (which this guard exists to block).

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/b05ac92a88b4ee8e. Report an issue: GitHub.