{"record":{"id":"33909460d0bcc78c","repo":"MHSanaei/3x-ui","slug":"s-s-w","errorCode":null,"errorMessage":"%s %s: %w","messagePattern":"%s %s: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/runtime/remote.go","lineNumber":251,"sourceCode":"\t}\n\treq.Header.Set(\"Accept\", \"application/json\")\n\tif contentType != \"\" {\n\t\treq.Header.Set(\"Content-Type\", contentType)\n\t}\n\tif hashHex != \"\" {\n\t\treq.Header.Set(wirecodec.HashHeader, hashHex)\n\t}\n\tif zstdEncoded {\n\t\treq.Header.Set(\"Content-Encoding\", wirecodec.EncodingZstd)\n\t}\n\n\tclient, err := r.httpClient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s %s: %w\", method, path, err)\n\t}\n\tdefer resp.Body.Close()\n\tr.recordCaps(resp.Header)\n\n\t// Validate status before reading a success payload: a non-OK response's\n\t// body is never used beyond a short diagnostic, so don't let a node force us\n\t// to buffer a large body just to return an HTTP error.\n\tif resp.StatusCode != http.StatusOK {\n\t\tsnippet, _ := io.ReadAll(io.LimitReader(resp.Body, errBodyDiagBytes))\n\t\tif msg := bytes.TrimSpace(snippet); len(msg) > 0 {\n\t\t\t// %q quotes/escapes the untrusted node body so control characters or\n\t\t\t// newlines in it can't garble or inject into the error/log output.\n\t\t\treturn nil, fmt.Errorf(\"%s %s: HTTP %d: %q\", method, path, resp.StatusCode, msg)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s %s: HTTP %d\", method, path, resp.StatusCode)\n\t}\n\n\t// Fast-fail on an honestly-declared oversize body; the LimitReader below is","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/runtime/remote.go#L233-L269","documentation":"Returned by Remote.do in internal/web/runtime/remote.go when the HTTP request to a remote sub-node fails before a response is received. The message wraps the underlying transport error (connection refused, DNS failure, TLS handshake error, timeout) with the HTTP method and API path that were attempted. It is the master-panel-side signal that the node endpoint at the configured address could not be reached at all.","triggerScenarios":"Calling any Remote RPC (UpdateInbound, AddClient, refreshRemoteIDs, ListInboundOptions...) while the node process is down, the node address/port is wrong, the panel-to-node URL uses https against a plain-HTTP listener (or vice versa), the mTLS client certificate is rejected, or the request exceeds the client's timeout budget (context deadline).","commonSituations":"Node server rebooted or x-ui service stopped; firewall/NAT rule dropped after infra change; node FQDN expired or DNS record removed; certificate rotated on the node so the pinned/verified TLS identity no longer matches; slow node so every RPC times out.","solutions":["Check the node is running and its panel port is listening: curl -vk https://<node-addr>/panel/ from the master.","Verify the node's address, port and certificate settings in the master's node form match what the node actually serves.","Look at the wrapped cause at the end of the message: 'connection refused' = wrong port/down service, 'certificate is valid for' = hostname/SNI mismatch, 'context deadline exceeded' = timeout — fix accordingly.","If the cause is a timeout on large inbounds, raise the RPC timeout or reduce the payload (fewer clients per inbound) rather than retrying blindly."],"exampleFix":"// before: node registered as http://10.0.0.5:54321 but panel serves TLS\n// node form: Address = http://10.0.0.5:54321  -> GET http://10.0.0.5:54321/panel/api/inbounds/list: ...: http: server gave HTTP response to HTTPS client\n\n// after: match the scheme the node actually listens on\n// node form: Address = https://10.0.0.5:54321 (and install the node cert) -> RPC succeeds","handlingStrategy":"retry","validationCode":"// Before a batch of RPCs, verify the node endpoint answers at all\nfunc nodeReachable(ctx context.Context, nodeURL string) error {\n    req, _ := http.NewRequestWithContext(ctx, http.MethodHead, strings.TrimSuffix(nodeURL, \"/\")+\"/\", nil)\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return err\n    }\n    resp.Body.Close()\n    return nil\n}","typeGuard":"func isTransportError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \": \") &&\n        (errors.Is(err, context.DeadlineExceeded) ||\n         errors.Is(err, context.Canceled) ||\n         strings.Contains(err.Error(), \"connection refused\") ||\n         strings.Contains(err.Error(), \"no such host\"))\n}","tryCatchPattern":"if err := remote.UpdateInbound(ctx, before, after); err != nil {\n    if isTransportError(err) { // transient: let reconcile retry\n        markNodeDirty(nodeID)\n        return nil\n    }\n    return err\n}","preventionTips":["Keep node address/port/cert in the master node form exactly matching what the node serves; verify with curl after any node-side TLS change.","Monitor node heartbeat status and alert before operators issue bulk writes against an offline node.","Use one source of truth for node connectivity — never edit the node's external address without updating the master record."],"tags":["network","http","node-sync","runtime","remote"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}