XTLS/Xray-core · error
Failed to build sockopt.
Error message
Failed to build sockopt.
What it means
Thrown when streamSettings.sockopt is set but SocketSettings.Build() fails. It is a wrapper: the underlying error (chained with .Base(err)) typically comes from invalid socket options such as a bad mark, dangling dialer/redirect strategy, or an unusable bind address. The outer message only tells you the failure is in the sockopt block.
Source
Thrown at infra/conf/transport_internet.go:198
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "httpupgrade",
Settings: serial.ToTypedMessage(hs),
})
}
if c.HysteriaSettings != nil {
hs, err := c.HysteriaSettings.Build()
if err != nil {
return nil, errors.New("Failed to build Hysteria config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "hysteria",
Settings: serial.ToTypedMessage(hs),
})
}
if c.SocketSettings != nil {
ss, err := c.SocketSettings.Build()
if err != nil {
return nil, errors.New("Failed to build sockopt.").Base(err)
}
config.SocketSettings = ss
}
if c.FinalMask != nil {
for _, mask := range c.FinalMask.Tcp {
u, err := mask.Build(true)
if err != nil {
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
}
config.Tcpmasks = append(config.Tcpmasks, serial.ToTypedMessage(u))
}
for _, mask := range c.FinalMask.Udp {
u, err := mask.Build(false)
if err != nil {
return nil, errors.New("failed to build mask with type ", mask.Type).Base(err)
}
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))View on GitHub (pinned to 7d214f8b09)
Solutions
- Inspect the full error chain; the Base(err) message identifies the exact sockopt field that failed.
- Check every field under sockopt against SocketConfig in infra/conf (valid ranges and enum values).
- Temporarily remove the sockopt block to confirm the rest of the config builds, then re-add fields one by one.
Example fix
// before
"sockopt": { "domainStrategy": "UseIPv4Only", "tcpKeepAliveInterval": -1 }
// after
"sockopt": { "domainStrategy": "UseIPv4Only", "tcpKeepAliveInterval": 100 } Defensive patterns
Strategy: try-catch
Validate before calling
// sanity-check sockopt numbers before handing config to xray
func sockoptLooksValid(so map[string]any) bool {
if v, ok := so["tcpKeepAliveInterval"].(float64); ok && v < 0 { return false }
if v, ok := so["tcpKeepAliveIdle"].(float64); ok && v < 0 { return false }
return true
} Type guard
func hasSockopt(s map[string]any) bool {
ss, ok := s["streamSettings"].(map[string]any)
if !ok { return false }
_, present := ss["sockopt"]
return present
} Try / catch
if err := buildConfig(doc); err != nil {
if strings.Contains(err.Error(), "Failed to build sockopt.") {
// surface the Base(err) cause to the user with the offending sockopt field
}
return err
} Prevention
- Validate sockopt values against the current SocketConfig struct after every xray upgrade.
- Avoid platform-specific sockopt values (mark, interface) on machines that lack them.
- Use a config linter/schema validator in the deployment pipeline.
When it happens
Trigger: Config contains "sockopt": { ... } with invalid contents, e.g. tcpKeepAliveInterval out of range, a bad domainStrategy value, or a dialerProxy tag that fails to resolve during sockopt building.
Common situations: Hand-editing sockopt copied from another machine (e.g. tcpFastOpen / mark values not supported on the platform); typos in enum-like strings such as domainStrategy; using an old sockopt schema with a newer binary.
Related errors
- bridge tag is empty
- bridge domain is empty
- portal tag is empty
- portal domain is empty
- unknown action: {}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/d76a3b9b82f8ee92.
Report an issue: GitHub.