fatedier/frp · error
decode proxy at index %d: %w
Error message
decode proxy at index %d: %w
What it means
DecodeClientConfigJSON iterates raw.Proxies and decodes each entry with DecodeProxyConfigurerJSON; any per-entry failure is wrapped with the entry's index as 'decode proxy at index %d: %w'. The %w verb preserves the underlying cause chain (unknown type, field mismatch, plugin error), and the index points at which proxies[] element in the client config JSON is broken.
Source
Thrown at pkg/config/v1/decode.go:175
Proxies []jsonx.RawMessage `json:"proxies,omitempty"`
Visitors []jsonx.RawMessage `json:"visitors,omitempty"`
}
raw := rawClientConfig{}
if err := decodeJSONWithOptions(b, &raw, options); err != nil {
return ClientConfig{}, err
}
cfg := ClientConfig{
ClientCommonConfig: raw.ClientCommonConfig,
Proxies: make([]TypedProxyConfig, 0, len(raw.Proxies)),
Visitors: make([]TypedVisitorConfig, 0, len(raw.Visitors)),
}
for i, proxyData := range raw.Proxies {
proxyCfg, err := DecodeProxyConfigurerJSON(proxyData, options)
if err != nil {
return ClientConfig{}, fmt.Errorf("decode proxy at index %d: %w", i, err)
}
cfg.Proxies = append(cfg.Proxies, TypedProxyConfig{
Type: proxyCfg.GetBaseConfig().Type,
ProxyConfigurer: proxyCfg,
})
}
for i, visitorData := range raw.Visitors {
visitorCfg, err := DecodeVisitorConfigurerJSON(visitorData, options)
if err != nil {
return ClientConfig{}, fmt.Errorf("decode visitor at index %d: %w", i, err)
}
cfg.Visitors = append(cfg.Visitors, TypedVisitorConfig{
Type: visitorCfg.GetBaseConfig().Type,
VisitorConfigurer: visitorCfg,
})
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Parse the index from the message and inspect that element of proxies[] (0-based) in the source config.
- Apply the fix indicated by the wrapped cause error (type name, field type, or plugin block) to that element.
- Re-run the loader; repeat for any further indexed failures.
Example fix
# error: decode proxy at index 2: unknown proxy type: Tcp # before (proxies[2]) [[proxies]] type = "Tcp" # after [[proxies]] type = "tcp"
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: validate each proxies[] entry individually to report positions, not just the wrapped index error.
func lintProxies(b []byte, opts v1.DecodeOptions) error {
var probe struct {
Proxies []json.RawMessage `json:"proxies"`
}
if err := json.Unmarshal(b, &probe); err != nil {
return err
}
for i, raw := range probe.Proxies {
if _, err := v1.DecodeProxyConfigurerJSON(raw, opts); err != nil {
return fmt.Errorf("proxies[%d]: %w", i, err)
}
}
return nil
} Try / catch
if _, err := v1.DecodeClientConfigJSON(b, opts); err != nil {
var msg string
if errors.As(err, &msg); strings.Contains(err.Error(), "decode proxy at index") {
// extract index from the message; the %w chain holds the root cause for errors.Unwrap
}
return err
} Prevention
- Decode proxies[] entries one-by-one in tooling so failures carry stable positions.
- Use errors.Unwrap/errors.As to reach the root cause under the index wrapper.
- Diff generated configs against a known-good schema before rollout.
When it happens
Trigger: Loading a client config JSON/TOML where the Nth element of proxies[] (0-based) has an unknown type, a wrong-typed field, or a bad plugin block. The wrapped message after the colon is the real cause; the index identifies the array element.
Common situations: Large configs where the index is essential to find the bad entry among dozens; programmatic config generation producing one malformed element; partial upgrades where only some entries use newer field names.
Related errors
- unknown proxy type: %s
- unmarshal ProxyConfig error: %v
- decode visitor at index %d: %w
- unmarshal proxy plugin error: %v
- unknown visitor type: %s
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/ba242c210da0e4f4.
Report an issue: GitHub.