{"record":{"id":"882a82aa75ddeffb","repo":"XTLS/Xray-core","slug":"failed-to-unmarshal-extra","errorCode":null,"errorMessage":"Failed to unmarshal \"extra\".","messagePattern":"Failed to unmarshal \"extra\"\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_method.go","lineNumber":311,"sourceCode":"\tCMaxReuseTimes   Int32Range `json:\"cMaxReuseTimes\"`\n\tHMaxRequestTimes Int32Range `json:\"hMaxRequestTimes\"`\n\tHMaxReusableSecs Int32Range `json:\"hMaxReusableSecs\"`\n\tHKeepAlivePeriod int64      `json:\"hKeepAlivePeriod\"`\n}\n\nfunc newRangeConfig(input Int32Range) *splithttp.RangeConfig {\n\treturn &splithttp.RangeConfig{\n\t\tFrom: input.From,\n\t\tTo:   input.To,\n\t}\n}\n\n// Build implements Buildable.\nfunc (c *SplitHTTPConfig) Build() (proto.Message, error) {\n\tif c.Extra != nil {\n\t\tvar extra SplitHTTPConfig\n\t\tif err := json.Unmarshal(c.Extra, &extra); err != nil {\n\t\t\treturn nil, errors.New(`Failed to unmarshal \"extra\".`).Base(err)\n\t\t}\n\t\textra.Host = c.Host\n\t\textra.Path = c.Path\n\t\textra.Mode = c.Mode\n\t\tc = &extra\n\t}\n\n\tswitch c.Mode {\n\tcase \"\":\n\t\tc.Mode = \"auto\"\n\tcase \"auto\", \"packet-up\", \"stream-up\", \"stream-one\":\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported mode: \" + c.Mode)\n\t}\n\n\t// Priority (client): host > serverName > address\n\tfor k := range c.Headers {\n\t\tif strings.ToLower(k) == \"host\" {","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_method.go#L293-L329","documentation":"SplitHTTPConfig.Build() found a non-null \"extra\" field (json.RawMessage at transport_method.go:287) but json.Unmarshal of its bytes into another SplitHTTPConfig failed at line 310. \"extra\" is a merge mechanism: settings nested under \"extra\" override the top-level ones (except host/path/mode, which are re-forced from the outer config at lines 313-315). The error means those bytes are not valid JSON shaped like a splithttp settings object.","triggerScenarios":"Any splithttp transportSettings containing \"extra\": <value> where value is not unmarshalable into SplitHTTPConfig: a JSON string or number (\"extra\": \"foo\"), a JSON array, malformed JSON fragment, or an object whose fields have wrong types (\"xPaddingBytes\": 100 instead of {\"from\":..,\"to\":..}, \"headers\": [..] instead of an object, \"xmux\": true).","commonSituations":"Users migrating splithttp tuning knobs into \"extra\" after reading third-party guides; accidental double-encoded JSON (a quoted string containing JSON); copy-paste from YAML-converted configs where nesting got flattened; trailing commas inside extra.","solutions":["Make \"extra\" a JSON object mirroring SplitHTTPConfig field names/types: \"extra\": { \"xPaddingBytes\": { \"from\": 100, \"to\": 1000 } }","Verify every nested type: ranges are objects with from/to, headers is an object of string->string, xmux is an object","Lint the config with jq to confirm extra parses as an object","Drop \"extra\" entirely — it is optional; set tuning knobs at top level instead"],"exampleFix":"// before\n\"extra\": \"{\\\"xPaddingBytes\\\":{\\\"from\\\":100}}\"\n// after\n\"extra\": { \"xPaddingBytes\": { \"from\": 100, \"to\": 1000 } }","handlingStrategy":"validation","validationCode":"// Go: pre-validate that \"extra\" unmarshals into the splithttp settings shape\nif cfg.Extra != nil {\n\tvar probe map[string]json.RawMessage\n\tif err := json.Unmarshal(cfg.Extra, &probe); err != nil {\n\t\treturn fmt.Errorf(\"extra must be a JSON object: %w\", err)\n\t}\n\tif v, ok := probe[\"xPaddingBytes\"]; ok {\n\t\tvar r struct{ From, To int32 }\n\t\tif json.Unmarshal(v, &r) != nil {\n\t\t\treturn errors.New(\"extra.xPaddingBytes must be {\\\"from\\\":n,\\\"to\\\":n}\")\n\t\t}\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := splithttpConf.Build(); err != nil {\n\tif strings.Contains(err.Error(), `Failed to unmarshal \"extra\"`) {\n\t\t// re-run json.Unmarshal on Extra locally to get the precise offset/type error\n\t}\n}","preventionTips":["\"extra\" must be a plain JSON object, never a string or array","Mirror the exact field names/types of the top-level splithttp settings","Do not double-encode extra as a quoted JSON string"],"tags":["config","splithttp","json","validation"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}