fatedier/frp · error
type is required
Error message
type is required
What it means
DecodeProxyConfigurerJSON (pkg/config/v1/decode.go:46) rejects a JSON null payload for a proxy configurer with 'type is required'. The decoder needs a typed envelope {"type": "tcp"|..., ...} to select the concrete config struct; null carries no type, so there is nothing to instantiate. (A present-but-unknown type instead yields 'unknown proxy type: ...'.)
Source
Thrown at pkg/config/v1/decode.go:46
func decodeJSONWithOptions(b []byte, out any, options DecodeOptions) error {
return jsonx.UnmarshalWithOptions(b, out, jsonx.DecodeOptions{
RejectUnknownMembers: options.DisallowUnknownFields,
})
}
func isJSONNull(b []byte) bool {
return len(b) == 0 || string(b) == "null"
}
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 {View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Send an object with a valid type field: {"type":"tcp","name":"ssh",...}
- Omit the entry entirely instead of serializing null
- Filter null entries out of arrays before decoding
- If a typed nil can reach the encoder, skip marshaling it (omitempty / nil check)
Example fix
// before
raw := []byte("null")
cfg, err := v1.DecodeProxyConfigurerJSON(raw, opts) // type is required
// after
raw := []byte(`{"type":"tcp","name":"ssh","remotePort":22}`)
cfg, err := v1.DecodeProxyConfigurerJSON(raw, opts) Defensive patterns
Strategy: type-guard
Validate before calling
if len(b) == 0 || string(b) == "null" {
return fmt.Errorf("proxy entry is null; an object with \"type\" is required")
} Type guard
func isDecodableProxyJSON(b []byte) bool {
s := strings.TrimSpace(string(b))
return s != "" && s != "null"
} Try / catch
cfg, err := v1.DecodeProxyConfigurerJSON(b, opts)
if err != nil {
if strings.Contains(err.Error(), "type is required") {
return nil, fmt.Errorf("null proxy config in payload at %s", path)
}
return nil, err
} Prevention
- Skip or reject null entries before decoding arrays of proxies
- Use omitempty / nil checks when serializing so nulls never reach the store
- Distinguish 'type is required' (null) from 'unknown proxy type' (bad type string)
When it happens
Trigger: Decoding a proxy entry that is literal null — e.g. an API/store payload where a proxy slot was set to null, or json.Marshal of a nil pointer written into the store file then read back and decoded.
Common situations: Automation writing JSON null placeholders into proxy arrays; partial updates serialized from maps with nil values; hand-edited store/config JSON containing null entries.
Related errors
- ErrHealthCheckType
- failed to decode proxy at index %d: %w
- failed to decode visitor at index %d: %w
- ErrInvalidArgument
- ErrNotFound
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/043f65dcd4f2ab74.
Report an issue: GitHub.