XTLS/Xray-core · error

tcpFastOpen: only boolean and integer value is acceptable

Error message

tcpFastOpen: only boolean and integer value is acceptable

What it means

Thrown while building SocketConfig from a 'sockopt' JSON block. The 'tcpFastOpen' (tfo) field only accepts a JSON boolean or a number; after JSON decoding any number arrives as float64, and the type switch only handles bool and float64. Any other JSON type (string, array, object, null-shaped non-nil weirdness) reaches the default branch and this error is returned.

Source

Thrown at infra/conf/transport_sockopt.go:82

	HappyEyeballsSettings *HappyEyeballsConfig   `json:"happyEyeballs"`
	TrustedXForwardedFor  []string               `json:"trustedXForwardedFor"`
}

// Build implements Buildable.
func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
	tfo := int32(0) // don't invoke setsockopt() for TFO
	if c.TFO != nil {
		switch v := c.TFO.(type) {
		case bool:
			if v {
				tfo = 256
			} else {
				tfo = -1 // TFO need to be disabled
			}
		case float64:
			tfo = int32(math.Min(v, math.MaxInt32))
		default:
			return nil, errors.New("tcpFastOpen: only boolean and integer value is acceptable")
		}
	}
	var tproxy internet.SocketConfig_TProxyMode
	switch strings.ToLower(c.TProxy) {
	case "tproxy":
		tproxy = internet.SocketConfig_TProxy
	case "redirect":
		tproxy = internet.SocketConfig_Redirect
	default:
		tproxy = internet.SocketConfig_Off
	}

	dStrategy := internet.DomainStrategy_AS_IS
	switch strings.ToLower(c.DomainStrategy) {
	case "asis", "":
		dStrategy = internet.DomainStrategy_AS_IS
	case "useip":
		dStrategy = internet.DomainStrategy_USE_IP

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Change the value to a JSON boolean: "tcpFastOpen": true (enable) or false (disable)
  2. Or use an integer queue length: "tcpFastOpen": 256
  3. Remove the tcpFastOpen key entirely if TFO behavior is not needed

Example fix

// before
"sockopt": { "tcpFastOpen": "true" }
// after
"sockopt": { "tcpFastOpen": true }
Defensive patterns

Strategy: validation

Validate before calling

// before marshalling config, validate sockopt.tcpFastOpen
func validTFO(v interface{}) bool {
    switch v.(type) {
    case bool, float64, int, int64, json.Number:
        return true
    }
    return false
}
if raw, ok := sockopt["tcpFastOpen"]; ok && !validTFO(raw) {
    return fmt.Errorf("tcpFastOpen must be bool or number, got %T", raw)
}

Prevention

When it happens

Trigger: Setting "sockopt": { "tcpFastOpen": "true" } (string instead of bool), "tcpFastOpen": [256], or "tcpFastOpen": { "enabled": true } in any inbound/outbound/streamSettings socket options, then loading the config.

Common situations: Copy-pasting a config from a wiki/blog that quoted the value ("true" instead of true), or a YAML-to-JSON conversion that turned the bare word true into a string.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/3c60f7c8914be4c9. Report an issue: GitHub.