fatedier/frp · error

failed to decode proxy at index %d: %w

Error message

failed to decode proxy at index %d: %w

What it means

While loading the store, DecodeProxyConfigurerJSON failed for the i-th element of the proxies array. Decoding is two-stage: the entry's "type" discriminator must map to a registered ProxyConfigurer type, then the payload must unmarshal into that type. Because DisallowUnknownFields is false, unknown fields alone do NOT trigger this — a bad/missing "type" string or a structurally incompatible payload does.

Source

Thrown at pkg/config/source/store.go:99

	type rawStoreData struct {
		Proxies  []jsonx.RawMessage `json:"proxies,omitempty"`
		Visitors []jsonx.RawMessage `json:"visitors,omitempty"`
	}
	stored := rawStoreData{}
	if err := jsonx.Unmarshal(data, &stored); err != nil {
		return fmt.Errorf("failed to parse JSON: %w", err)
	}

	s.proxies = make(map[string]v1.ProxyConfigurer)
	s.visitors = make(map[string]v1.VisitorConfigurer)

	for i, proxyData := range stored.Proxies {
		proxyCfg, err := v1.DecodeProxyConfigurerJSON(proxyData, v1.DecodeOptions{
			DisallowUnknownFields: false,
		})
		if err != nil {
			return fmt.Errorf("failed to decode proxy at index %d: %w", i, err)
		}
		name := proxyCfg.GetBaseConfig().Name
		if name == "" {
			return fmt.Errorf("proxy name cannot be empty")
		}
		s.proxies[name] = proxyCfg
	}

	for i, visitorData := range stored.Visitors {
		visitorCfg, err := v1.DecodeVisitorConfigurerJSON(visitorData, v1.DecodeOptions{
			DisallowUnknownFields: false,
		})
		if err != nil {
			return fmt.Errorf("failed to decode visitor at index %d: %w", i, err)
		}
		name := visitorCfg.GetBaseConfig().Name
		if name == "" {
			return fmt.Errorf("visitor name cannot be empty")

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Open the store file, navigate to the proxies array element at the index reported in the error message (index is 0-based)
  2. Verify its "type" value is one of the proxy types supported by the RUNNING frp version (tcp, udp, xtcp, stcp, sudp, http, https, tcpmux, plugin variants)
  3. If the type is from a newer frp release, upgrade frp to at least the version that wrote the file
  4. Fix the typo'd/missing "type" field or remove the offending entry, then retry

Example fix

// before (store.json, proxies[2])
{ "type": "htp", "name": "dashboard" }

// after
{ "type": "http", "name": "dashboard" }
Defensive patterns

Strategy: validation

Validate before calling

var supportedProxyTypes = map[string]bool{
	"tcp": true, "udp": true, "xtcp": true, "stcp": true, "sudp": true,
	"http": true, "https": true, "tcpmux": true,
}

func validateStoreTypes(path string) error {
	data, _ := os.ReadFile(path)
	var raw struct {
		Proxies []json.RawMessage `json:"proxies"`
	}
	if json.Unmarshal(data, &raw) != nil {
		return nil // parse errors handled separately
	}
	for i, p := range raw.Proxies {
		var t struct{ Type string `json:"type"` }
		if json.Unmarshal(p, &t) != nil || !supportedProxyTypes[t.Type] {
			return fmt.Errorf("proxies[%d]: unsupported type %q for this frp build", i, t.Type)
		}
	}
	return nil
}

Try / catch

if _, err := source.NewStoreSource(cfg); err != nil {
	var idx int
	if _, e := fmt.Sscanf(err.Error(), "failed to decode proxy at index %d", &idx); e == nil {
		// point operator at the exact array element, suggest version mismatch
	}
}

Prevention

When it happens

Trigger: A stored proxy entry whose "type" is misspelled ("tcp" vs "tpc") or missing; a store file written by a NEWER frp version containing a proxy type this older build does not know; an entry where the value of "type" is not a string; a payload that cannot unmarshal into the target config struct (e.g. remotePort as a string).

Common situations: Downgrading frp after a newer release wrote modern proxy types into the store; hand-authoring the store file with the wrong discriminator name; a custom/enterprise proxy type that was compiled in before but not in the current binary.

Understand the failure class

Related errors


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