XTLS/Xray-core · error

invalid header

Error message

invalid header 

What it means

A header-preset Build in infra/conf/transport_finalmask.go:626 maps well-known camouflage header names to numeric IDs (""->domain-based 0, dtls->1, srtp->2, utp->3, wechat->4, wireguard->5) for the header.Config used by mkcp-style masking. Any unrecognized "header" value fails with "invalid header " + the offending name.

Source

Thrown at infra/conf/transport_finalmask.go:626

	switch strings.ToLower(c.Header) {
	case "dns":
		domain := c.Value
		if len(domain) == 0 {
			domain = "www.baidu.com"
		}
		return &header.Config{ID: 0, Domain: domain}, nil
	case "dtls":
		return &header.Config{ID: 1}, nil
	case "srtp":
		return &header.Config{ID: 2}, nil
	case "utp":
		return &header.Config{ID: 3}, nil
	case "wechat":
		return &header.Config{ID: 4}, nil
	case "wireguard":
		return &header.Config{ID: 5}, nil
	default:
		return nil, errors.New("invalid header ", c.Header)
	}
}

type Salamander struct {
	Password   string     `json:"password"`
	PacketSize Int32Range `json:"packetSize"`
}

func (c *Salamander) Build() (proto.Message, error) {
	if c.PacketSize.To > 0 {
		if c.PacketSize.From <= 0 || c.PacketSize.To > 2048 {
			return nil, errors.New("gecko: invalid min/max packet size")
		}
		return &salamander.GeckoConfig{
			Password:      c.Password,
			MinPacketSize: c.PacketSize.From,
			MaxPacketSize: c.PacketSize.To,
		}, nil

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Use exactly one of: dtls, srtp, utp, wechat, wireguard (lowercase), or omit "header"
  2. Verify the header value against the current preset list for your Xray version
  3. Prefer copy-paste from the official transport docs over retyping

Example fix

// before
"header": { "type": "none", "header": "srtp" }
// after (drop the invalid wrapper/preset)
"header": { "type": "none" }  // or "header": { "type": "srpcamouflage", "header": "srtp" } per docs
// simplest: ensure the preset string is exactly "srtp" lowercase in the field this builder reads
Defensive patterns

Strategy: validation

Validate before calling

const HEADERS = new Set(['', 'dtls', 'srtp', 'utp', 'wechat', 'wireguard']);
if (!HEADERS.has(headerCfg.header ?? '')) throw new Error(`invalid header preset: ${headerCfg.header}`);

Type guard

const isHeaderPreset = (h: string) => ['', 'dtls', 'srtp', 'utp', 'wechat', 'wireguard'].includes(h);

Prevention

When it happens

Trigger: "header":"wechat-video", "header":"DTLS" (case-sensitive switch), "header":"video". Omitting header or leaving it empty is valid and uses the domain form.

Common situations: Copying kcp header presets from older docs/forks with renamed options; case mismatch; typos in the preset name.

Related errors


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