{"record":{"id":"613fc72b95808a1a","repo":"rqlite/rqlite","slug":"remote-remove-node-not-authorized","errorCode":null,"errorMessage":"remote remove node not authorized","messagePattern":"remote remove node not authorized","errorType":"http","errorClass":null,"httpStatus":401,"severity":"warning","filePath":"http/service.go","lineNumber":577,"sourceCode":"\t}\n\n\trn := &proto.RemoveNodeRequest{\n\t\tId: remoteID,\n\t}\n\n\taddr, err := s.proxy.Remove(r.Context(), rn, makeCredentials(r), qp.Timeout(defaultTimeout), qp.Redirect())\n\tif err != nil {\n\t\tif errors.Is(err, proxy.ErrNotLeader) {\n\t\t\ts.DoRedirect(w, r, qp)\n\t\t\treturn\n\t\t}\n\t\tif errors.Is(err, proxy.ErrLeaderNotFound) {\n\t\t\tstats.Add(numLeaderNotFound, 1)\n\t\t\thttp.Error(w, proxy.ErrLeaderNotFound.Error(), http.StatusServiceUnavailable)\n\t\t\treturn\n\t\t}\n\t\tif errors.Is(err, proxy.ErrUnauthorized) {\n\t\t\thttp.Error(w, \"remote remove node not authorized\", http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(ServedByHTTPHeader, addr)\n}\n\n// handleSQLAnalyze handles requests to analyze and show SQL rewriting.\nfunc (s *Service) handleSQLAnalyze(w http.ResponseWriter, r *http.Request, qp QueryParams) {\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\n\tif !s.CheckRequestPerm(r, auth.PermQuery) {\n\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\treturn\n\t}\n\n\tif r.Method != \"GET\" && r.Method != \"POST\" {","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/rqlite/rqlite/blob/7586a4d1bdbd9a5a80021664c5a863cd850adb60/http/service.go#L559-L595","documentation":"In http.Service.handleRemove, when the leader-forwarded remove-node call returns proxy.ErrUnauthorized, the handler responds HTTP 401 with the literal body 'remote remove node not authorized'. This means the remote leader rejected the node-remove request because the client's basic-auth credentials are missing or lack permission for the operation. It is an authentication/authorization failure, not a transport or cluster-state problem.","triggerScenarios":"DELETE /db/node on an auth-enabled cluster without credentials, with wrong username/password, or with a user lacking sufficient permission level for node removal (join/remove operations require elevated auth).","commonSituations":"Cluster deployed with -auth but automation scripts not updated to send credentials; auth config changed (users recreated) leaving old credentials invalid; reverse proxy stripping the Authorization header; users created with too-low permission level.","solutions":["Send valid basic-auth credentials of a user with sufficient permissions: curl -XDELETE -u 'user:pass' ...","Check the node's auth configuration / create or elevate a user permitted to remove nodes.","Verify no intermediate proxy strips the Authorization header.","Re-test; if 401 persists, confirm the credentials against the auth config on the leader node."],"exampleFix":"// before\ncurl -XDELETE 'localhost:4001/db/node?addr=1.2.3.4:4002'  # 401 remote remove node not authorized\n// after\ncurl -XDELETE -u 'admin:secret' 'localhost:4001/db/node?addr=1.2.3.4:4002'","handlingStrategy":"validation","validationCode":"function assertRemoveAuth(creds) {\n  if (!creds || !creds.username || !creds.password) {\n    throw new Error('rqlite auth enabled: basic-auth credentials required for node removal')\n  }\n}","typeGuard":null,"tryCatchPattern":"const res = await fetch(url, {method:'DELETE', headers:{Authorization: basicAuth(user, pass)}})\nif (res.status === 401 && (await res.text()).includes('not authorized')) {\n  // refresh credentials / verify user permission level, then retry\n  throw new Error('node removal rejected: invalid or insufficient credentials')\n}","preventionTips":["Store rqlite credentials in a secret manager and inject into automation configs.","Provision an admin-level user specifically for cluster administration tasks.","Check that reverse proxies pass the Authorization header through unchanged.","Rotate credentials consistently across all nodes and clients; test after auth changes."],"tags":["http","auth","unauthorized"],"backgroundTag":"unauthorized-request","analyzedSha":"7586a4d1bdbd9a5a80021664c5a863cd850adb60","analyzedAt":"2026-09-03T07:03:02.260Z","contentChangedAt":"2026-09-03T07:03:02.260Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}