{"record":{"id":"c0439b21ffd7454b","repo":"MHSanaei/3x-ui","slug":"node-is-disabled","errorCode":null,"errorMessage":"node is disabled","messagePattern":"node is disabled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/node.go","lineNumber":776,"sourceCode":"\tif err := db.Model(model.Node{}).Where(\"id = ?\", id).Update(\"enable\", enable).Error; err != nil {\n\t\treturn err\n\t}\n\tif mgr := runtime.GetManager(); mgr != nil {\n\t\tmgr.InvalidateNode(id)\n\t}\n\treturn nil\n}\n\n// GetWebCertFiles asks a node for its own web TLS certificate/key file paths,\n// used by \"Set Cert from Panel\" so a node-assigned inbound gets paths that\n// exist on the node rather than the central panel. See issue #4854.\nfunc (s *NodeService) GetWebCertFiles(id int) (*runtime.WebCertFiles, error) {\n\tn, err := s.GetById(id)\n\tif err != nil || n == nil {\n\t\treturn nil, fmt.Errorf(\"node not found\")\n\t}\n\tif !n.Enable {\n\t\treturn nil, fmt.Errorf(\"node is disabled\")\n\t}\n\tmgr := runtime.GetManager()\n\tif mgr == nil {\n\t\treturn nil, fmt.Errorf(\"runtime manager unavailable\")\n\t}\n\tremote, err := mgr.RemoteFor(n)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\treturn remote.GetWebCertFiles(ctx)\n}\n\n// NodeUpdateResult reports the outcome of triggering a panel self-update on one\n// node so the UI can show per-node success/failure for a bulk request.\ntype NodeUpdateResult struct {\n\tId    int    `json:\"id\"`","sourceCodeStart":758,"sourceCodeEnd":794,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/node.go#L758-L794","documentation":"Returned by NodeService.GetWebCertFiles when the node row exists but n.Enable is false. Disabled nodes have no live Remote/runtime handle by design, so the panel refuses to contact them and fails fast with this message before touching the runtime manager.","triggerScenarios":"Calling getWebCertFiles (Set Cert from Panel) for a node whose Enable toggle is off — disabled temporarily for maintenance, disabled because it was offline, or never re-enabled after setup.","commonSituations":"Admin disabled the node during an incident and the UI still offers cert actions on its inbounds; automation hitting the endpoint for all nodes regardless of enable state.","solutions":["Re-enable the node (toggle in the nodes list) once it is healthy, then retry the cert fetch.","If the node is intentionally disabled, enter cert paths manually on the inbound instead of fetching from the node.","Make automation skip disabled nodes: check the node's enable flag before calling cert/node RPCs.","Investigate why the node was disabled — repeated health failures usually point at the connectivity issues behind errors 100-105."],"exampleFix":"// before: node id=5 disabled\n// err: node is disabled\n\n// after: enable node 5 in the panel (and confirm it is reachable), then retry getWebCertFiles","handlingStrategy":"validation","validationCode":"n, err := nodeSvc.GetById(id)\nif err != nil || n == nil { return errors.New(\"node not found\") }\nif !n.Enable { return errors.New(\"node disabled: enable it or use manual cert paths\") }","typeGuard":"func isNodeDisabled(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"node is disabled\")\n}","tryCatchPattern":"files, err := nodeSvc.GetWebCertFiles(id)\nif err != nil {\n    if isNodeDisabled(err) {\n        return nil, errUnavailable(\"node disabled; enable node or enter cert paths manually\")\n    }\n    return nil, err\n}","preventionTips":["Have UI/automation check the node's enable flag before offering node-dependent actions.","Re-enable nodes promptly after maintenance so cert and sync flows recover.","Investigate WHY a node is disabled — persistent disablement usually traces back to the connectivity errors (100-105)."],"tags":["node-management","validation","lifecycle","api"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}