{"record":{"id":"525ae43ba686e353","repo":"mihomo-party-org/clash-party","slug":"core-not-ready-after-core-ready-max-retries-att","errorCode":null,"errorMessage":"Core not ready after ${CORE_READY_MAX_RETRIES} attempts, proceeding anyway","messagePattern":"Core not ready after (.+?) attempts, proceeding anyway","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/main/core/process.ts","lineNumber":162,"sourceCode":"  }\n}\n\nexport async function waitForCoreReady(): Promise<void> {\n  for (let i = 0; i < CORE_READY_MAX_RETRIES; i++) {\n    try {\n      const axios = await getAxios(true)\n      await axios.get('/')\n      managerLogger.info(\n        `Core ready after ${i + 1} attempts (${(i + 1) * CORE_READY_RETRY_INTERVAL_MS}ms)`\n      )\n      return\n    } catch {\n      if (i === 0) {\n        managerLogger.info('Waiting for core to be ready...')\n      }\n\n      if (i === CORE_READY_MAX_RETRIES - 1) {\n        managerLogger.warn(\n          `Core not ready after ${CORE_READY_MAX_RETRIES} attempts, proceeding anyway`\n        )\n        return\n      }\n\n      await new Promise((resolve) => setTimeout(resolve, CORE_READY_RETRY_INTERVAL_MS))\n    }\n  }\n}\n\nfunction normalizeProcessName(name: string): string {\n  return name\n    .trim()\n    .replace(/\\.exe$/i, '')\n    .toLowerCase()\n}\n\nexport async function verifyProcessOwner(","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/main/core/process.ts#L144-L180","documentation":"waitForCoreReady polls the mihomo controller API until it responds or CORE_READY_MAX_RETRIES attempts elapse. On the final failed attempt it logs this warning and returns anyway, letting callers (startMihomoApiStreams) proceed with stream setup against a possibly unready core. It indicates the core was slow to start or the controller endpoint never became reachable.","triggerScenarios":"All CORE_READY_MAX_RETRIES poll attempts throw (connection refused) because the core takes longer than retries*CORE_READY_RETRY_INTERVAL_MS to open its external-controller port, or the core failed to start entirely (bad config, port in use).","commonSituations":"Slow disk/AV scanning the mihomo binary on first launch; external-controller port occupied by another process; core crashing immediately due to invalid YAML so it never listens.","solutions":["Check core startup logs for a crash or config error — if the core died, fix that root cause first.","Increase CORE_READY_MAX_RETRIES or CORE_READY_RETRY_INTERVAL_MS on slow machines so polling outlives real startup time.","Verify the external-controller address/port is correct and not occupied; confirm the controller secret matches."],"exampleFix":"// before\n// proceed after retries silently\n// after\nif (!(await waitForControllerReady(30_000))) {\n  managerLogger.error('Core controller never became ready; aborting stream setup')\n  return // or restart core\n}","handlingStrategy":"retry","validationCode":"const reachable = await fetch(`http://${controllerHost}:${controllerPort}`, { signal: AbortSignal.timeout(2000) }).then(r => r.ok, () => false)\nif (!reachable) await restartCore()","typeGuard":null,"tryCatchPattern":"try {\n  await waitForCoreReady()\n} catch {\n  managerLogger.warn('core readiness check failed; verifying before streaming')\n  if (!(await isControllerReachable())) await restartCore()\n}","preventionTips":["Size retries*interval to exceed worst-case core startup (cold disk, AV scanning).","Detect core process exit during polling and abort early instead of waiting out all retries.","Log elapsed startup time to tune the constants against real machines."],"tags":["startup","core","timeout","retry"],"backgroundTag":"core-not-ready-timeout","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}