{"record":{"id":"c6f01cfcbc9a4cd1","repo":"MHSanaei/3x-ui","slug":"local-xray-is-not-running","errorCode":null,"errorMessage":"local xray is not running","messagePattern":"local xray is not running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/runtime/local.go","lineNumber":38,"sourceCode":"\ntype Local struct {\n\tdeps LocalDeps\n\tmu   sync.Mutex\n}\n\nfunc NewLocal(deps LocalDeps) *Local {\n\treturn &Local{deps: deps}\n}\n\nfunc (l *Local) Name() string { return \"local\" }\n\nfunc (l *Local) withAPI(fn func(api *xray.XrayAPI) error) error {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tport := l.deps.APIPort()\n\tif port <= 0 {\n\t\treturn errors.New(\"local xray is not running\")\n\t}\n\tvar api xray.XrayAPI\n\tif err := api.Init(port); err != nil {\n\t\treturn err\n\t}\n\tdefer api.Close()\n\treturn fn(&api)\n}\n\nfunc (l *Local) AddInbound(_ context.Context, ib *model.Inbound) error {\n\tif ib.Protocol == model.MTProto {\n\t\tinst, ok := mtproto.InstanceFromInbound(ib)\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\treturn mtproto.GetManager().Ensure(inst)\n\t}\n\tbody, err := json.MarshalIndent(ib.GenXrayInboundConfig(), \"\", \"  \")","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/runtime/local.go#L20-L56","documentation":"Thrown by the local runtime adapter (internal/web/runtime/local.go) inside withAPI. Before every gRPC call to the local Xray child process it reads the configured Xray API port; when APIPort() returns <= 0 there is no port to connect to, so the runtime refuses the call with 'local xray is not running'. It means the panel either has not started Xray yet or is running with no API listener configured, not that a connection attempt failed.","triggerScenarios":"Any state-changing inbound/client operation dispatched through runtime.Runtime while the local Xray child process is down: calling InboundService add/update/del flows before xray.Start() succeeded, after a crash that has not been restarted (eventbus xray.crash), or when the xray API port setting is 0/unset so APIPort() returns 0.","commonSituations":"Panel startup ordering bugs (service jobs firing before Xray is up), Xray binary missing or failing to launch so the API port is never registered, a setting migration that wiped the apiPort value, or tests that construct LocalDeps without wiring APIPort.","solutions":["Verify the Xray child process is actually running (panel logs / xray process status) and restart it from the panel","Check the Xray API port setting in the panel (must be > 0 and not collide with an inbound port)","If this fires at startup, fix the initialization order so runtime-dependent jobs and handlers only run after xray is started","In tests, make the fake LocalDeps.APIPort() return a positive value"],"exampleFix":"// before\nport := l.deps.APIPort()\nif port <= 0 {\n    return errors.New(\"local xray is not running\")\n}\n\n// after (caller side: start xray before dispatching)\nif err := xray.StartXray(); err != nil { return err }\nreturn runtime.AddInbound(ctx, ib)","handlingStrategy":"validation","validationCode":"port := getAPIPortSetting() // same source LocalDeps.APIPort reads\nif port <= 0 {\n    return fmt.Errorf(\"cannot dispatch: xray API port unset; start xray first\")\n}\nreturn runtime.AddInbound(ctx, ib)","typeGuard":null,"tryCatchPattern":"if err := runtime.AddInbound(ctx, ib); err != nil {\n    if strings.Contains(err.Error(), \"local xray is not running\") {\n        // start/restart xray, then retry once\n    }\n}","preventionTips":["Ensure xray.StartXry/xray.StartXray completes before any runtime dispatch","Keep the Xray API port setting non-zero and stable across migrations","In tests, wire a fake LocalDeps with a positive APIPort"],"tags":["xray","runtime","startup-order","grpc"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}