{"record":{"id":"f6f6bd80fde9206a","repo":"v2rayA/v2rayA","slug":"outbound-group-is-required","errorCode":null,"errorMessage":"outbound group is required","messagePattern":"outbound group is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/server/controller/customInbound.go","lineNumber":44,"sourceCode":"\tif ci.Protocol != \"socks\" && ci.Protocol != \"http\" {\n\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"protocol must be socks or http\")))\n\t\treturn\n\t}\n\tif ci.Port <= 0 || ci.Port > 65535 {\n\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"invalid port\")))\n\t\treturn\n\t}\n\tif ci.Tag == \"\" {\n\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"tag is required\")))\n\t\treturn\n\t}\n\tif net.ParseIP(\"0.0.0.0:\"+fmt.Sprint(ci.Port)) == nil {\n\t\t// basic port check already done above\n\t}\n\n\t// Validate outbound binding\n\tif ci.Outbound == \"\" {\n\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"outbound group is required\")))\n\t\treturn\n\t}\n\tif ci.OutboundType != \"direct\" && ci.OutboundType != \"routingA\" {\n\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"outboundType must be 'direct' or 'routingA'\")))\n\t\treturn\n\t}\n\n\t// Verify the outbound group exists\n\toutbounds := configure.GetOutbounds()\n\toutboundExists := false\n\tfor _, ob := range outbounds {\n\t\tif ob == ci.Outbound {\n\t\t\toutboundExists = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !outboundExists {\n\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"outbound group '%s' does not exist\", ci.Outbound)))","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/service/server/controller/customInbound.go#L26-L62","documentation":"A custom inbound must be bound to an outbound group; ci.Outbound names which group (e.g. \"proxy\" or \"direct\"-style group) the inbound traffic is fed into. PostCustomInbound rejects an empty Outbound field.","triggerScenarios":"POST /custom-inbound with ci.Outbound == \"\" — the outbound field is omitted or explicitly empty.","commonSituations":"Clients unaware the outbound binding is mandatory; copying payloads from older API versions where the outbound defaulted implicitly.","solutions":["Set outbound to an existing outbound group name (commonly \"proxy\")","Update client payloads to always include the outbound field","Check configure.GetOutbounds() (GET outbounds) for valid group names before posting"],"exampleFix":"// before\n{\"protocol\":\"socks\",\"port\":1080,\"tag\":\"in1\",\"outbound\":\"\",\"outboundType\":\"direct\"}\n// after\n{\"protocol\":\"socks\",\"port\":1080,\"tag\":\"in1\",\"outbound\":\"proxy\",\"outboundType\":\"direct\"}","handlingStrategy":"validation","validationCode":"if ci.Outbound == \"\" { return errors.New(\"outbound group is required\") }","typeGuard":"func hasOutbound(ci CustomInbound) bool { return ci.Outbound != \"\" }","tryCatchPattern":"if err := postCustomInbound(ci); strings.Contains(err.Error(), \"outbound group is required\") { ci.Outbound = \"proxy\"; retry }","preventionTips":["Default outbound to \"proxy\" in client payloads","Fetch the outbound list first and pick from it","Include outbound in every custom inbound payload"],"tags":["validation","api","routing","go"],"backgroundTag":"missing-required-argument","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}