{"record":{"id":"a3d4842656b01011","repo":"janhq/jan","slug":"router-failed-its-health-check-on-backend-target","errorCode":null,"errorMessage":"Router failed its health check on backend ${targetBackendString}","messagePattern":"Router failed its health check on backend (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"extensions/llamacpp-extension/src/index.ts","lineNumber":1925,"sourceCode":"      if (IS_WINDOWS) {\n        await new Promise((resolve) => setTimeout(resolve, 1000))\n      }\n\n      await this.commitBackendSelection(version, backend)\n\n      if (await this.restartRouterAndProbe()) {\n        logger.info(`Successfully updated to backend: ${targetBackendString}`)\n        await this.pruneOldBackendVersions(version, backend)\n        await this.recordUpdateHistory({\n          from,\n          to: targetBackendString,\n          outcome: 'updated',\n          durationMs: Date.now() - startedAt,\n        })\n        return { wasUpdated: true, newBackend: targetBackendString }\n      }\n\n      throw new Error(\n        `Router failed its health check on backend ${targetBackendString}`\n      )\n    } catch (error) {\n      logger.error('Backend update failed:', error)\n      const rollbackOutcome = await this.rollbackBackendSelection(previous)\n      await this.recordUpdateHistory({\n        from,\n        to: targetBackendString,\n        outcome:\n          rollbackOutcome === 'not-attempted' ? 'failed' : rollbackOutcome,\n        error: String(error),\n        durationMs: Date.now() - startedAt,\n      })\n      return { wasUpdated: false, newBackend: this.config.version_backend }\n    } finally {\n      this.isUpdatingBackend = false\n      this.currentUpdate = null\n    }","sourceCodeStart":1907,"sourceCodeEnd":1943,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/llamacpp-extension/src/index.ts#L1907-L1943","documentation":"Post-update health-check failure: after downloading and switching to the new backend, restartRouterAndProbe() is called to restart the llama.cpp router and probe it. If the probe fails (router did not come up healthy), the update is considered failed and the error propagates. The catch block then attempts a rollback via rollbackBackendSelection.","triggerScenarios":"The new backend binary launched but crashed or hung: missing shared libraries (e.g. CUDA runtime DLLs not installed), incompatible GPU driver, port conflict on the router's listen port, the binary segfaulted on startup, or the health probe timed out.","commonSituations":"Switching from CPU to CUDA backend without the matching CUDA toolkit/driver installed; switching to a backend version with a known startup regression; another process occupying the router port; GPU out of memory at launch.","solutions":["Check the router logs for the crash reason — missing .so/.dll or GPU errors are the most common.","If switching to a CUDA backend, ensure the CUDA runtime DLLs are installed (installCudaRuntime) and the GPU driver is compatible.","Verify no other process is using the router's listen port.","Allow the automatic rollback to restore the previous working backend; if rollback also fails, manually select a known-good backend."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await extension.runUpdate(targetBackendString)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('health check')) {\n    // rollback is automatic; inform the user and suggest checking GPU/CUDA setup\n    console.error('Update failed; previous backend restored. Check GPU drivers and CUDA runtime.')\n  } else {\n    throw e\n  }\n}","preventionTips":["Before switching to a GPU backend, verify the GPU driver and CUDA toolkit version match the backend requirements.","Install CUDA runtime DLLs (installCudaRuntime) before switching to a CUDA backend.","Check that the router port is not occupied by another process before triggering an update."],"tags":["backend","health-check","router","gpu","rollback","typescript"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}