larksuite/cli · critical
proxy plugin config is invalid: %w
Error message
proxy plugin config is invalid: %w
What it means
The cached fail-closed transport wraps the stored loadErr: the proxy plugin config file exists but Load() returned an error (malformed or unreadable). Every request through pluginTransport is blocked with this error instead of silently using direct egress, and the result is cached to avoid rebuilding per call.
Source
Thrown at internal/transport/transport.go:23
import (
"fmt"
"net/http"
"net/url"
"sync"
)
// proxyPluginTransport is a fixed-proxy clone of http.DefaultTransport (with optional
// custom root CA), lazily built on first use when proxy plugin mode is enabled.
var proxyPluginTransport = sync.OnceValue(buildProxyPluginTransport)
// cachedBlockedTransport is a fail-closed transport cached on first use when
// the proxy plugin config exists but is invalid. This avoids cloning
// http.DefaultTransport on every pluginTransport call.
var cachedBlockedTransport = sync.OnceValue(buildBlockedTransport)
func buildBlockedTransport() http.RoundTripper {
return failClosedTransport(fmt.Errorf("proxy plugin config is invalid: %w", loadErr))
}
func buildProxyPluginTransport() http.RoundTripper {
def, ok := http.DefaultTransport.(*http.Transport)
if !ok {
// Cannot clone the stdlib transport. Fail closed with a concrete
// *http.Transport (not a bare RoundTripper) so downcasting callers such
// as Fallback cannot silently degrade this into a
// direct-egress transport.
return failClosedTransport(fmt.Errorf("proxy plugin transport unavailable: http.DefaultTransport is %T, want *http.Transport", http.DefaultTransport))
}
cfg, err := Load()
if err != nil {
// Fail closed: config file exists but is malformed/unreadable — do not
// silently fall back to direct egress.
return blockedTransport(def, fmt.Errorf("proxy plugin config is invalid: %w", err))
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Open the proxy plugin config file and fix JSON/schema errors (run a JSON validator).
- Fix file permissions so the CLI user can read the config.
- Delete the proxy plugin config file if proxy mode is not needed, so the CLI falls back to direct egress.
Example fix
// before (proxy config)
{"enabled": true, "url": "http://proxy:8080",,}
// after
{"enabled": true, "url": "http://proxy:8080"} Defensive patterns
Strategy: try-catch
Validate before calling
var cfg map[string]any
if err := json.Unmarshal(cfgBytes, &cfg); err != nil {
log.Fatalf("proxy plugin config is not valid JSON: %v", err)
} Try / catch
tr, err := pluginTransport()
if err != nil && strings.Contains(err.Error(), "proxy plugin config is invalid") {
log.Fatalf("fix proxy plugin config: %v", err)
} Prevention
- Generate the config with tooling (jq/yq) instead of hand-editing JSON.
- Validate the config file after every write.
- Remove the config file when proxy mode is not in use.
When it happens
Trigger: Proxy plugin config file present but invalid JSON/permission-denied, then any CLI HTTP request goes through pluginTransport -> cachedBlockedTransport -> buildBlockedTransport.
Common situations: Hand-edited proxy config file with a JSON syntax error; config written by root with no read permission; partially written file from an interrupted update.
Related errors
- proxy plugin enabled but config is invalid: %w
- invalid %s %q: fragment is not allowed
- proxy plugin transport unavailable: http.DefaultTransport is
- multiple plugins called Restrict; only one plugin may own th
- environment variable %q is not allowlisted in provider
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/3eeaec349892967b.
Report an issue: GitHub.