fatedier/frp · error
unknown proxy type: %s
Error message
unknown proxy type: %s
What it means
DecodeProxyConfigurerJSON in pkg/config/v1/decode.go dispatches on the JSON envelope's "type" field to construct the right ProxyConfigurer via NewProxyConfigurerByType. If the type string does not match any registered proxy type (tcp, udp, xtcp, stcp, sudp, tcpmux, http, https, plugin variants), the factory returns nil and this error names the offending type. It fires before any field-level decoding of the proxy object.
Source
Thrown at pkg/config/v1/decode.go:56
type typedEnvelope struct {
Type string `json:"type"`
Plugin jsonx.RawMessage `json:"plugin,omitempty"`
}
func DecodeProxyConfigurerJSON(b []byte, options DecodeOptions) (ProxyConfigurer, error) {
if isJSONNull(b) {
return nil, errors.New("type is required")
}
var env typedEnvelope
if err := jsonx.Unmarshal(b, &env); err != nil {
return nil, err
}
configurer := NewProxyConfigurerByType(ProxyType(env.Type))
if configurer == nil {
return nil, fmt.Errorf("unknown proxy type: %s", env.Type)
}
if err := decodeJSONWithOptions(b, configurer, options); err != nil {
return nil, fmt.Errorf("unmarshal ProxyConfig error: %v", err)
}
if len(env.Plugin) > 0 && !isJSONNull(env.Plugin) {
plugin, err := DecodeClientPluginOptionsJSON(env.Plugin, options)
if err != nil {
return nil, fmt.Errorf("unmarshal proxy plugin error: %v", err)
}
configurer.GetBaseConfig().Plugin = plugin
}
return configurer, nil
}
func DecodeVisitorConfigurerJSON(b []byte, options DecodeOptions) (VisitorConfigurer, error) {
if isJSONNull(b) {
return nil, errors.New("type is required")View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Set "type" to a supported built-in value: tcp, udp, xtcp, stcp, sudp, tcpmux, http, or https.
- Check case and whitespace — the match is exact and lowercase.
- For plugin-based proxies, keep type as the transport (e.g. "tcp") and put the plugin name under plugin.type, not in the proxy type field.
Example fix
// before
{ "type": "Tcp", "localPort": 80 }
// after
{ "type": "tcp", "localPort": 80 } Defensive patterns
Strategy: validation
Validate before calling
// Check the proxy type against known types before decoding.
var knownProxyTypes = map[string]bool{
"tcp": true, "udp": true, "xtcp": true, "stcp": true,
"sudp": true, "tcpmux": true, "http": true, "https": true,
}
func validProxyType(t string) error {
if !knownProxyTypes[t] {
return fmt.Errorf("unknown proxy type %q; want one of tcp,udp,xtcp,stcp,sudp,tcpmux,http,https", t)
}
return nil
} Type guard
func isKnownProxyType(t string) bool { return knownProxyTypes[t] } Try / catch
if cfg, err := v1.DecodeProxyConfigurerJSON(b, opts); err != nil {
if strings.Contains(err.Error(), "unknown proxy type") {
// surface the type string and list supported types to the operator
}
return err
} Prevention
- Keep proxy types lowercase and exactly spelled.
- Pin your config schema to your frp version's supported types.
- Put plugin names in plugin.type, never in proxy type.
When it happens
Trigger: Calling DecodeProxyConfigurerJSON (directly, or via DecodeClientConfigJSON over a proxies[] entry) with a proxy whose "type" is misspelled or unregistered, e.g. "Tcp" (case-sensitive), "web", "grpc", or a plugin name placed in "type" instead of "plugin.type". Also when the JSON lacks quotes/has a broken type field value that still unmarshals.
Common situations: Upgrading from frp versions whose accepted type sets differ; using a third-party proxy type from a plugin ecosystem not compiled into this build; case mismatches ('TCP' vs 'tcp'); putting the plugin name into proxy "type" (e.g. type="static_file" instead of type="tcp" + plugin settings).
Related errors
- unmarshal ProxyConfig error: %v
- decode proxy at index %d: %w
- unmarshal proxy plugin error: %v
- unknown visitor type: %s
- unmarshal VisitorConfig error: %v
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/1d75deb09a9db364.
Report an issue: GitHub.