{"record":{"id":"03b2a27205523591","repo":"janhq/jan","slug":"invalid-backend-string-targetbackendstring-sup","errorCode":null,"errorMessage":"Invalid backend string: ${targetBackendString} supplied to update function","messagePattern":"Invalid backend string: (.+?) supplied to update function","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/llamacpp-extension/src/index.ts","lineNumber":1874,"sourceCode":"    }\n\n    // `runUpdate` clears currentUpdate inside its own body, so a queued\n    // continuation chained onto it always observes an idle slot.\n    this.currentUpdate = this.runUpdate(targetBackendString)\n    return this.currentUpdate\n  }\n\n  private async runUpdate(\n    targetBackendString: string\n  ): Promise<{ wasUpdated: boolean; newBackend: string }> {\n    this.isUpdatingBackend = true\n    const startedAt = Date.now()\n    const from = this.config.version_backend\n    let previous: BackendSelection | undefined\n\n    try {\n      if (!targetBackendString)\n        throw new Error(\n          `Invalid backend string: ${targetBackendString} supplied to update function`\n        )\n\n      const backendParts = targetBackendString.split('/')\n\n      if (\n        backendParts.length !== 2 ||\n        !backendParts[0]?.trim() ||\n        !backendParts[1]?.trim()\n      ) {\n        throw new Error(\n          `Invalid backend string format: \"${targetBackendString}\". Expected \"version/backend\".`\n        )\n      }\n\n      const [rawVersion, rawBackend] = backendParts\n      const version = rawVersion.trim()\n      const backend = rawBackend.trim()","sourceCodeStart":1856,"sourceCodeEnd":1892,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/llamacpp-extension/src/index.ts#L1856-L1892","documentation":"Guard at the top of runUpdate: if targetBackendString is falsy (empty string, null, undefined), the function throws immediately before any string parsing. This prevents downstream split('/') logic from operating on a meaningless input.","triggerScenarios":"Calling runUpdate with an empty string, null, or undefined — typically because a caller failed to resolve a backend selection or passed a stale/uninitialized value.","commonSituations":"A UI dropdown selection event fired with no value; a stored backend preference was cleared but the update was still triggered; a race condition where the backend selection was reset between user click and handler execution.","solutions":["Validate that targetBackendString is a non-empty string before calling runUpdate.","Fix the caller to guarantee a resolved 'version/backend' string (see error 9 for format validation).","Guard the UI so the update action is disabled when no backend is selected."],"exampleFix":"// before\nthis.runUpdate(selectedBackend)  // selectedBackend could be ''\n// after\nif (!selectedBackend) throw new Error('No backend selected')\nthis.runUpdate(selectedBackend)","handlingStrategy":"validation","validationCode":"function isValidBackendString(s: unknown): s is string {\n  return typeof s === 'string' && s.length > 0\n}\n\n// Before calling runUpdate:\nif (!isValidBackendString(targetBackendString)) {\n  throw new Error('A non-empty backend string is required')\n}","typeGuard":"function isNonEmptyBackendString(s: unknown): s is string {\n  return typeof s === 'string' && s.trim().length > 0\n}","tryCatchPattern":null,"preventionTips":["Disable the update UI action when no backend is selected.","Initialize backend selection state to null and check before triggering update."],"tags":["backend","validation","update","typescript"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}