larksuite/cli · error

download proxy selection is missing

Error message

download proxy selection is missing

What it means

This error is thrown by the download transport's Proxy callback when the request context does not carry a pre-selected proxy URL under selectedDownloadProxyKey{}. The download path first calls selectProxy once and freezes the result into the request context so a stateful selector cannot flip the second dial to direct egress; the per-request Proxy function then only reads that frozen value. If the key is absent or holds a non-*url.URL value, the transport refuses to proceed rather than silently going direct.

Source

Thrown at internal/validate/url.go:360

	selectProxy := source.Proxy
	direct := cloneDownloadHTTPTransport(source)
	direct.Proxy = nil
	configureDirectDownloadTransport(direct)
	if selectProxy == nil {
		return direct, true
	}

	// The proxied branch validates the requested URL before construction and
	// on every redirect. Its TCP peer is the selected proxy, so applying the
	// direct-origin IP guard there would incorrectly reject trusted loopback or
	// private-network proxies. Freeze the selected proxy in request context so
	// a stateful selector cannot switch the second lookup to direct egress.
	proxied := cloneDownloadHTTPTransport(source)
	proxied.Proxy = func(req *http.Request) (*url.URL, error) {
		selected, ok := req.Context().Value(selectedDownloadProxyKey{}).(*url.URL)
		if !ok || selected == nil {
			return nil, fmt.Errorf("download proxy selection is missing")
		}
		cloned := *selected
		return &cloned, nil
	}
	return &proxyAwareDownloadTransport{
		selectProxy:        selectProxy,
		direct:             direct,
		proxied:            proxied,
		lookupIP:           lookupIP,
		proxiedByTLSServer: make(map[string]*http.Transport),
	}, true
}

func cloneDownloadHTTPTransport(source *http.Transport) *http.Transport {
	cloned := source.Clone()
	if cloned.TLSNextProto == nil {
		if _, ok := source.TLSNextProto["h2"]; ok {
			cloned.ForceAttemptHTTP2 = true

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Ensure the request passed through the normal download flow that calls selectProxy and stores the result in the context under selectedDownloadProxyKey{} before the transport dials
  2. Do not replace or strip the request Context (context.Background()/TODO) between selection and dialing
  3. Verify the value stored in the context is *url.URL, not a string or wrapper type
  4. If constructing requests in tests, set the context value explicitly: req = req.WithContext(context.WithValue(ctx, selectedDownloadProxyKey{}, proxyURL))

Example fix

// before
req, _ := http.NewRequestWithContext(context.Background(), "GET", url, nil)
resp, err := proxiedClient.Do(req) // selection lost
// after
ctx = context.WithValue(ctx, selectedDownloadProxyKey{}, selectedProxy)
req, _ = http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := proxiedClient.Do(req)
Defensive patterns

Strategy: validation

Validate before calling

func hasSelectedDownloadProxy(ctx context.Context) bool {
    sel, ok := ctx.Value(selectedDownloadProxyKey{}).(*url.URL)
    return ok && sel != nil
}
// before sending: if !hasSelectedDownloadProxy(req.Context()) { re-run the select-and-freeze step }

Type guard

sel, ok := req.Context().Value(selectedDownloadProxyKey{}).(*url.URL)
if !ok || sel == nil { /* selection missing — restore before dialing */ }

Try / catch

if err := runDownload(ctx, req); err != nil && strings.Contains(err.Error(), "download proxy selection is missing") {
    // rebuild the request via the normal download entrypoint so selection runs again
}

Prevention

When it happens

Trigger: An http.Request is sent through proxyAwareDownloadTransport's proxied transport without the context value set by the select-then-freeze step (e.g. the request bypassed cloneDownloadHTTPTransport's selection phase, the context was replaced/derived with a new background, or the selection step stored a wrong type).

Common situations: Reusing an http.Client/transport built for the proxied download path with requests created elsewhere; wrapping or re-writing the request context in middleware; tests constructing requests by hand against the pinned transport; a selector returning a value stored under a different context key after refactoring.

Related errors


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