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,
}, nilView on GitHub (pinned to 7d214f8b09)
Solutions
- Use exactly one of: dtls, srtp, utp, wechat, wireguard (lowercase), or omit "header"
- Verify the header value against the current preset list for your Xray version
- 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
- Copy preset names verbatim from current docs (lowercase)
- Re-validate header presets after upgrading Xray versions
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
- invalid randRange
- Invalid PacketsFrom
- PacketsFrom can't be 0
- last lengths entry min can't be 0
- len(item.Packet) > 0 && item.Rand.To > 0
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/a4f874b0db4824ed.
Report an issue: GitHub.