{"record":{"id":"379a2be37309d46b","repo":"netbirdio/netbird","slug":"at-least-one-target-is-required","errorCode":null,"errorMessage":"at least one target is required","messagePattern":"at least one target is required","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/reverseproxy/service/service.go","lineNumber":864,"sourceCode":"\treturn &proto.AccessRestrictions{\n\t\tAllowedCidrs:     r.AllowedCIDRs,\n\t\tBlockedCidrs:     r.BlockedCIDRs,\n\t\tAllowedCountries: r.AllowedCountries,\n\t\tBlockedCountries: r.BlockedCountries,\n\t\tCrowdsecMode:     r.CrowdSecMode,\n\t}\n}\n\nfunc (s *Service) Validate() error {\n\tif s.Name == \"\" {\n\t\treturn errors.New(\"service name is required\")\n\t}\n\tif len(s.Name) > 255 {\n\t\treturn errors.New(\"service name exceeds maximum length of 255 characters\")\n\t}\n\n\tif len(s.Targets) == 0 {\n\t\treturn errors.New(\"at least one target is required\")\n\t}\n\n\tif s.Mode == \"\" {\n\t\ts.Mode = ModeHTTP\n\t}\n\n\tif err := validateHeaderAuths(s.Auth.HeaderAuths); err != nil {\n\t\treturn err\n\t}\n\tif err := validateAccessRestrictions(&s.Restrictions); err != nil {\n\t\treturn err\n\t}\n\tif err := s.validatePrivateRequirements(); err != nil {\n\t\treturn err\n\t}\n\n\tswitch s.Mode {\n\tcase ModeHTTP:","sourceCodeStart":846,"sourceCodeEnd":882,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/reverseproxy/service/service.go#L846-L882","documentation":"Returned by Service.Validate (management/internals/modules/reverseproxy/service/service.go:864) when the Targets slice is empty. A reverse-proxy service forwards traffic to its target list, so a service with zero targets has nothing to proxy and is rejected before mode defaults are applied.","triggerScenarios":"Creating or updating a service with no Targets array, or with the array present but empty ([]), including updates intended to clear all targets.","commonSituations":"UI allows saving before a target is added; API client sends {\"targets\": []}; a plan to 'create now, add targets later' via API, which the model does not permit.","solutions":["Include at least one target (e.g. http://host:port) in the create/update request.","Validate client-side that the targets array is non-empty before calling.","If you intended to remove a target, keep at least one remaining or delete the service instead."],"exampleFix":"# before\n{\"name\": \"internal-api\", \"mode\": \"http\", \"domain\": \"api.example.net\", \"targets\": []}\n\n# after\n{\"name\": \"internal-api\", \"mode\": \"http\", \"domain\": \"api.example.net\", \"targets\": [\"http://10.0.0.5:8080\"]}","handlingStrategy":"validation","validationCode":"if len(svc.Targets) == 0 {\n    return fmt.Errorf(\"at least one target is required\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not model 'create now, target later'; the API requires a target at creation.","Disable submit in UIs until the targets list has at least one entry."],"tags":["go","netbird","management","reverse-proxy","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}