{"record":{"id":"45ab05a1e25675c5","repo":"MHSanaei/3x-ui","slug":"s-s-http-d-q","errorCode":null,"errorMessage":"%s %s: HTTP %d: %q","messagePattern":"(.+?) (.+?): HTTP (.+?): %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/runtime/remote.go","lineNumber":264,"sourceCode":"\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\n\t// the real guard since Content-Length is untrusted, may be absent, or is -1\n\t// under transparent decompression.\n\tif resp.ContentLength > maxRemoteResponseBytes {\n\t\treturn nil, fmt.Errorf(\"%s %s: %w (content-length %d, cap %d)\", method, path, errRemoteResponseTooLarge, resp.ContentLength, maxRemoteResponseBytes)\n\t}\n\n\traw, err := readCappedBody(resp.Body, maxRemoteResponseBytes)\n\tif err != nil {\n\t\tif errors.Is(err, errRemoteResponseTooLarge) {\n\t\t\treturn nil, fmt.Errorf(\"%s %s: %w (cap %d bytes)\", method, path, err, maxRemoteResponseBytes)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"read body: %w\", err)\n\t}","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/runtime/remote.go#L246-L282","documentation":"Returned by Remote.do when the sub-node answers the RPC with a non-200 status AND a non-empty body. The first %d is the HTTP status code and %q is a short (capped at errBodyDiagBytes), quoted snippet of the node's response body, escaped so untrusted node output cannot inject into logs. It means the request reached the node but the node's HTTP layer rejected it before the JSON envelope could be produced.","triggerScenarios":"Any Remote RPC where the node returns 401/403 (node API token mismatch or mTLS rejected), 404 (node build predates the endpoint, e.g. getWebCertFiles or descendants on an old node), 405 (method changed between versions), or 500 (panic in the node handler).","commonSituations":"Master and node run different 3x-ui versions so an endpoint exists only on one side; the shared bearer/secret token was regenerated on the node but not on the master; a reverse proxy in front of the node intercepts the path and returns 401/403; node handler bug returns 500 with a stack-trace body.","solutions":["Read the status code: 401/403 -> re-enter the node's API credential on the master; 404 -> upgrade the node to a build that has the endpoint; 5xx -> inspect the quoted node-side message in the node's own logs.","Confirm master and node run the same release version (panel setting /node page or binary version).","If a reverse proxy fronts the node, bypass it or add an exception for /panel/api/ so auth headers pass through unchanged.","Re-test with curl using the same token the master uses to confirm the node accepts it."],"exampleFix":"// before: node still on an old build\n// err: GET panel/api/server/getWebCertFiles: HTTP 404: \"404 page not found\"\n\n// after: upgrade node binary to the same release as master, then retry\n// GET panel/api/server/getWebCertFiles -> 200 envelope","handlingStrategy":"try-catch","validationCode":"// Check version compatibility before calling newer endpoints\nif err := remote.CheckCompat(ctx); err != nil { // or compare reported versions\n    return fmt.Errorf(\"node incompatible: %w\", err)\n}","typeGuard":"func httpStatusOf(err error) (int, bool) {\n    // remote.go errors embed \"HTTP <code>\" for non-OK statuses\n    m := regexp.MustCompile(`HTTP (\\d{3})`).FindStringSubmatch(err.Error())\n    if m == nil { return 0, false }\n    code, _ := strconv.Atoi(m[1])\n    return code, true\n}","tryCatchPattern":"if err := remote.GetWebCertFiles(ctx); err != nil {\n    if code, ok := httpStatusOf(err); ok && code == http.StatusNotFound {\n        return nil // old node build: fall back to manual cert paths\n    }\n    return err\n}","preventionTips":["Run master and nodes on the same release; upgrade nodes immediately after the master.","Rotate API tokens on both sides in the same maintenance window.","Exclude /panel/api/ from any reverse-proxy auth/redirect rules in front of nodes."],"tags":["http","auth","version-mismatch","node-sync","remote"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}