{"record":{"id":"84aebe92935331c3","repo":"MHSanaei/3x-ui","slug":"node-port-must-be-1-65535","errorCode":null,"errorMessage":"node port must be 1-65535","messagePattern":"node port must be 1-65535","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/node.go","lineNumber":1115,"sourceCode":"\n\tfn(proxyURL)\n}\n\nfunc (s *NodeService) probe(ctx context.Context, n *model.Node, proxyURL string) (HeartbeatPatch, error) {\n\tpatch := HeartbeatPatch{LastHeartbeat: time.Now().Unix()}\n\n\taddr, err := netsafe.NormalizeHost(n.Address)\n\tif err != nil {\n\t\tpatch.LastError = err.Error()\n\t\treturn patch, err\n\t}\n\tscheme := n.Scheme\n\tif scheme != \"http\" && scheme != \"https\" {\n\t\tscheme = \"https\"\n\t}\n\tif n.Port <= 0 || n.Port > 65535 {\n\t\tpatch.LastError = \"node port must be 1-65535\"\n\t\treturn patch, errors.New(patch.LastError)\n\t}\n\tprobeURL := &url.URL{\n\t\tScheme: scheme,\n\t\tHost:   net.JoinHostPort(addr, strconv.Itoa(n.Port)),\n\t\tPath:   normalizeBasePath(n.BasePath) + \"panel/api/server/status\",\n\t}\n\n\treq, err := http.NewRequestWithContext(\n\t\tnetsafe.ContextWithAllowPrivate(ctx, n.AllowPrivateAddress),\n\t\thttp.MethodGet, probeURL.String(), nil)\n\tif err != nil {\n\t\tpatch.LastError = err.Error()\n\t\treturn patch, err\n\t}\n\tif n.ApiToken != \"\" {\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+n.ApiToken)\n\t}\n\treq.Header.Set(\"Accept\", \"application/json\")","sourceCodeStart":1097,"sourceCodeEnd":1133,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/node.go#L1097-L1133","documentation":"The node health probe validates n.Port before constructing the status URL (/panel/api/server/status) and rejects ports outside 1-65535. The value is written into patch.LastError so the node list UI shows it inline. Zero is the common case — a node saved without a port — and out-of-range values usually come from bad config sync or manual API writes.","triggerScenarios":"Adding a node via the API with port omitted (Go zero-value 0); a port string like '8443 ' parsed to 0; synced node data with a corrupted port field.","commonSituations":"Automation creating nodes without the port field; editing nodes directly in the DB; YAML/JSON config with port as string that coerced badly.","solutions":["Set a valid port (the remote panel's HTTPS port, e.g. 443 or 2053) on the node and save","Validate port in range before creating nodes from scripts","If it recurs, audit what writes the nodes table / sync payload for the port field"],"exampleFix":"// before\nnode.Port = 0 // omitted in payload\n\n// after\nport, err := strconv.Atoi(rawPort)\nif err != nil || port < 1 || port > 65535 {\n    return fmt.Errorf(\"invalid node port %q\", rawPort)\n}\nnode.Port = port","handlingStrategy":"validation","validationCode":"if node.Port < 1 || node.Port > 65535 {\n    return fmt.Errorf(\"node %s: port %d out of range\", node.Name, node.Port)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require the port field when creating nodes via API/UI","Parse ports with strconv.Atoi and range-check before saving","Audit sync payloads that can overwrite the port with 0"],"tags":["node","validation","network","sync"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}