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 = trueView on GitHub (pinned to 7fd6ef3c07)
Solutions
- 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
- Do not replace or strip the request Context (context.Background()/TODO) between selection and dialing
- Verify the value stored in the context is *url.URL, not a string or wrapper type
- 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
- Always start downloads from the library's download entrypoint, not by hand-rolling requests against the pinned transport
- Never overwrite a request's Context after proxy selection
- Keep the context key and value type (*url.URL) unchanged when refactoring
- Add a test asserting requests carry the frozen proxy value
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
- failed to parse TAT response (HTTP %d): %w
- download request URL is missing
- failed to parse response: %w
- content-range is empty
- unsupported content-range: %q
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/94b7db4b532a1996.
Report an issue: GitHub.