{"record":{"id":"2e19955eb186e7bb","repo":"janhq/jan","slug":"backend-update-failed","errorCode":null,"errorMessage":"Backend update failed","messagePattern":"Backend update failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web-app/src/hooks/useBackendUpdater.ts","lineNumber":391,"sourceCode":"        result?.wasUpdated === false &&\n        (result.reason === 'in_progress' || typeof result.reason === 'undefined')\n      ) {\n        // Benign no-op (e.g., another update is already in progress or the\n        // extension returned a no-op response without a reason). Do not treat\n        // this as a failure; just clear the local isUpdating flag.\n        setUpdateState((prev) => ({\n          ...prev,\n          isUpdating: false,\n        }))\n      } else if (\n        result?.wasUpdated === false &&\n        result.reason &&\n        result.reason !== 'in_progress'\n      ) {\n        // Explicit failure reason from extension: surface as an error.\n        throw new Error(`Backend update failed: ${result.reason}`)\n      } else {\n        throw new Error('Backend update failed')\n      }\n    } catch (error) {\n      console.error('Error updating backend:', error)\n      setUpdateState((prev) => ({\n        ...prev,\n        isUpdating: false,\n      }))\n      throw error\n    }\n  }, [updateState.updateInfo, updateState.isUpdating, syncStateToOtherInstances])\n\n  const installBackend = useCallback(async (filePath: string) => {\n    try {\n      // Get llamacpp extension instance\n      const allExtensions = ExtensionManager.getInstance().listExtensions()\n      const llamacppExtension =\n        ExtensionManager.getInstance().getByName('llamacpp-extension')\n","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/web-app/src/hooks/useBackendUpdater.ts#L373-L409","documentation":"The catch-all backend-update failure: `updateBackend` returned `wasUpdated: false` with no `reason` at all, or a shape that matched none of the handled branches (not `true`, not `false`+`in_progress`, not `false`+explicit-reason). It indicates the extension returned an unexpected or empty failure response.","triggerScenarios":"The extension resolved with an undefined/null result, an object missing `wasUpdated`, or `{ wasUpdated: false }` with no reason. Typically an extension bug, an older API version returning a different shape, or an unhandled internal path.","commonSituations":"Extension version that returns `{ ok: true }` instead of `{ wasUpdated: true }`; a thrown-but-swallowed error inside the extension that resolved to a bare rejection caught upstream; API contract drift between the hook and the extension.","solutions":["Update the llamacpp extension so its `updateBackend` returns the documented `{ wasUpdated, reason? }` shape.","Log the raw `rawResult` before branching to capture the unexpected shape.","Treat a missing `wasUpdated` as a soft failure and poll `checkBackendForUpdates` to confirm actual state."],"exampleFix":"// before\n} else {\n  throw new Error('Backend update failed')\n}\n\n// after\n} else {\n  console.error('updateBackend returned unexpected shape:', rawResult)\n  throw new Error('Backend update failed: the extension returned an unexpected response.')\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isWellFormedUpdateResult(r: unknown): r is { wasUpdated: boolean; reason?: string } {\n  return !!r && typeof (r as any).wasUpdated === 'boolean'\n}","tryCatchPattern":"const rawResult = await extension.updateBackend?.(targetBackendString)\nif (!isWellFormedUpdateResult(rawResult)) {\n  console.error('Unexpected updateBackend shape:', rawResult)\n  // Fall back to re-checking actual state\n  const info = await extension.checkBackendForUpdates?.()\n  toast[info?.updateNeeded ? 'error' : 'success'](\n    info?.updateNeeded ? 'Backend update status unclear' : 'Backend is up to date'\n  )\n  return\n}","preventionTips":["Log the raw extension response before branching to diagnose shape drift.","Update the extension so updateBackend returns the documented shape.","Treat ambiguous results as soft-failures and verify state via checkBackendForUpdates."],"tags":["llamacpp","backend","update","contract"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}