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

  1. Parse the index from the message and inspect that element of proxies[] (0-based) in the source config.
  2. Apply the fix indicated by the wrapped cause error (type name, field type, or plugin block) to that element.
  3. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/ba242c210da0e4f4. Report an issue: GitHub.