XTLS/Xray-core · error

invalid fakedns config

Error message

invalid fakedns config

What it means

Thrown by FakeDNSConfig.UnmarshalJSON when the fakedns JSON value matches neither a single pool object nor an array of pool objects. Xray accepts fakedns either as one {ipPool, lruSize} object or as a list of such objects; anything else (a string, number, or object with wrong shape that fails both unmarshal attempts) yields this error at JSON parse time, not Build time.

Source

Thrown at infra/conf/fakedns.go:45

			return json.Marshal(f.pool)
		} else if f.pools != nil {
			return json.Marshal(f.pools)
		}
	}
	return nil, errors.New("unexpected config state")
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (f *FakeDNSConfig) UnmarshalJSON(data []byte) error {
	var pool FakeDNSPoolElementConfig
	var pools []*FakeDNSPoolElementConfig
	switch {
	case json.Unmarshal(data, &pool) == nil:
		f.pool = &pool
	case json.Unmarshal(data, &pools) == nil:
		f.pools = pools
	default:
		return errors.New("invalid fakedns config")
	}
	return nil
}

func (f *FakeDNSConfig) Build() (*fakedns.FakeDnsPoolMulti, error) {
	fakeDNSPool := fakedns.FakeDnsPoolMulti{}

	if f.pool != nil {
		fakeDNSPool.Pools = append(fakeDNSPool.Pools, &fakedns.FakeDnsPool{
			IpPool:  f.pool.IPPool,
			LruSize: f.pool.LRUSize,
		})
		return &fakeDNSPool, nil
	}

	if f.pools != nil {
		for _, v := range f.pools {
			fakeDNSPool.Pools = append(fakeDNSPool.Pools, &fakedns.FakeDnsPool{IpPool: v.IPPool, LruSize: v.LRUSize})

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Use the object form: {"ipPool": "198.18.0.0/15", "lruSize": 65535} or the array form [{...}, {...}].
  2. Replace old bare-CIDR fakedns strings with the pool object.
  3. Ensure field types are string/int respectively; unknown keys are ignored but wrong types are not.
  4. Run `xray run -test -c config.json` to catch it before starting the service.

Example fix

// before
"fakedns": "198.18.0.0/15"

// after
"fakedns": {"ipPool": "198.18.0.0/15", "lruSize": 65535}
Defensive patterns

Strategy: validation

Validate before calling

function isFakeDNSPool(o) {
    return o && typeof o === 'object' &&
        (typeof o.ipPool === 'string' || typeof o.lruSize === 'number');
}
function isFakeDNSConfig(v) {
    return isFakeDNSPool(v) || (Array.isArray(v) && v.every(isFakeDNSPool));
}
if (!isFakeDNSConfig(cfg.dns?.fakedns)) throw new Error('fakedns must be a pool object or array of pools');

Type guard

function isFakeDNSPool(o: unknown): o is { ipPool?: string; lruSize?: number } {
  return typeof o === 'object' && o !== null &&
    (o as any).ipPool === undefined || typeof (o as any).ipPool === 'string';
}

Prevention

When it happens

Trigger: "fakedns": "1.2.3.4/24" (old pre-pool syntax), "fakedns": {"ipPool": 123} (wrong field types), or "fakedns": 42. json.Unmarshal into FakeDNSPoolElementConfig and into []*FakeDNSPoolElementConfig both fail, hitting the default branch.

Common situations: Upgrading from very old Xray/V2Ray configs where fakedns took a bare CIDR string; typos in field names (e.g. "ippool" vs "ipPool") making the strict unmarshal fail when types mismatch; nesting pools one level too deep.

Related errors


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