{"record":{"id":"47fa17b827072de8","repo":"XTLS/Xray-core","slug":"mtu-must-be-at-least-21","errorCode":null,"errorMessage":"Mtu must be at least 21","messagePattern":"Mtu must be at least 21","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_method.go","lineNumber":563,"sourceCode":"\t}\n\tif c.Tti != nil {\n\t\tconfig.Tti = *c.Tti\n\t}\n\tif c.UpCap != nil {\n\t\tconfig.UplinkCapacity = *c.UpCap\n\t}\n\tif c.DownCap != nil {\n\t\tconfig.DownlinkCapacity = *c.DownCap\n\t}\n\tif c.CwndMultiplier != nil {\n\t\tconfig.CwndMultiplier = *c.CwndMultiplier\n\t}\n\tif c.MaxSendingWindow != nil {\n\t\tconfig.MaxSendingWindow = *c.MaxSendingWindow\n\t}\n\n\tif config.Mtu < 21 {\n\t\treturn nil, errors.New(\"Mtu must be at least 21\").AtError()\n\t}\n\tif config.Tti < 10 || config.Tti > 1000 {\n\t\treturn nil, errors.New(\"invalid mKCP TTI: \", c.Tti).AtError()\n\t}\n\tif config.CwndMultiplier < 1 {\n\t\treturn nil, errors.New(\"CwndMultiplier must be at least 1\").AtError()\n\t}\n\tif config.GetSendingBufferSize() == 0 {\n\t\treturn nil, errors.New(\"MaxSendingWindow must be >= Mtu\").AtError()\n\t}\n\n\treturn config, nil\n}\n\ntype GRPCConfig struct {\n\tAuthority           string `json:\"authority\"`\n\tServiceName         string `json:\"serviceName\"`\n\tMultiMode           bool   `json:\"multiMode\"`","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_method.go#L545-L581","documentation":"Thrown by KCPConfig.Build() when building an mKCP transport config whose Mtu value is below 21. mKCP needs a minimum MTU of 21 bytes to fit its packet header (conv, cmd, frg, wnd, ts, sn, una fields), so anything smaller cannot carry a valid KCP frame. The check runs after JSON defaults are applied, so the value used is the effective one.","triggerScenarios":"Setting \"mtu\" (e.g. 1350) below 21 in the kcpSettings block of an outbound/inbound streamSettings, or omitting it while a custom value of 0/20 leaks in from a template or generator.","commonSituations":"Copy-pasted client configs with a truncated mtu value, config generators emitting mtu: 0, or users trying to 'tune' mKCP down for overhead and going below the protocol floor.","solutions":["Set kcpSettings.mtu to 21 or higher (1200-1400 is the usual range).","Remove the mtu field entirely to accept the default.","If a generator/template produced the config, fix it and re-emit."],"exampleFix":"// before\n\"kcpSettings\": { \"mtu\": 20, \"tti\": 50 }\n// after\n\"kcpSettings\": { \"mtu\": 1350, \"tti\": 50 }","handlingStrategy":"validation","validationCode":"// before building the transport\nif kcp.Mtu != nil && *kcp.Mtu < 21 {\n    return fmt.Errorf(\"mKCP mtu %d below minimum 21\", *kcp.Mtu)\n}","typeGuard":null,"tryCatchPattern":"err := json.Unmarshal(raw, &cfg)\nif err == nil {\n    if _, err = cfg.Build(); err != nil {\n        if strings.Contains(err.Error(), \"Mtu must be at least 21\") {\n            log.Printf(\"config error: raise kcpSettings.mtu to >= 21\")\n        }\n    }\n}","preventionTips":["Validate mKCP numeric ranges in your config loader before handing off to Build().","Keep a lint step that checks kcpSettings.mtu >= 21 in CI for generated configs."],"tags":["config","mkcp","transport","validation","go"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}