{"record":{"id":"d04144e6dea8c035","repo":"chatboxai/chatbox","slug":"invalid-knowledge-base-id","errorCode":null,"errorMessage":"Invalid knowledge base ID","messagePattern":"Invalid knowledge base ID","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/knowledge-base/ipc-handlers.ts","lineNumber":157,"sourceCode":"          scope.setExtra('documentParser', documentParser?.type)\n          sentry.captureException(error)\n        })\n        throw error\n      }\n    }\n  )\n\n  ipcMain.handle(\n    'kb:update',\n    async (\n      _event,\n      { id, name, rerankModel, visionModel }: { id: number; name?: string; rerankModel?: string; visionModel?: string }\n    ) => {\n      try {\n        log.info(`ipcMain: kb:update, id=${id}, name=${name}, rerankModel=${rerankModel}, visionModel=${visionModel}`)\n\n        if (!id || id <= 0) {\n          throw new Error('Invalid knowledge base ID')\n        }\n\n        if (!name && rerankModel === undefined && visionModel === undefined) {\n          return 0\n        }\n\n        const db = getDatabase()\n        let sql = 'UPDATE knowledge_base SET '\n        const args: (string | number)[] = []\n\n        if (name !== undefined) {\n          if (!name.trim()) {\n            throw new Error('Knowledge base name cannot be empty')\n          }\n          sql += 'name = ?'\n          args.push(name.trim())\n        }\n        if (rerankModel !== undefined) {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/main/knowledge-base/ipc-handlers.ts#L139-L175","documentation":"Thrown at the bottom of getModel() after both code paths (builtin registry via getProviderDefinition, and custom provider via getProviderSettings + isCustom) have been exhausted without returning a ModelInterface. It is the fallthrough for a provider id that exists in getProviderSettings (so providerBaseInfo was found) but is neither registered in the new registry nor flagged `isCustom` — an inconsistent state where the provider is known but has no factory.","triggerScenarios":"A provider id exists in globalSettings but is not in the builtin registry and is not marked `isCustom: true` (e.g. a half-migrated or hand-edited custom provider entry); a builtin provider was de-registered at runtime via clearProviderRegistry but its settings entry remains; the providerBaseInfo came from a stale source (e.g. old customProviders list) that lacks the `isCustom` flag; race between registry clear and model resolution.","commonSituations":"Manual edits to settings.json adding a provider object without `isCustom`; app version downgrade where a builtin provider id exists in the session but the older codebase lacks its registry entry; a custom provider import dropped the `isCustom` flag; plugin/provider extension unloaded but session still references it.","solutions":["Confirm the provider is either registered via defineProvider (check `getProviderDefinition(provider)` returns truthy) OR present in globalSettings.customProviders with `isCustom: true`.","Re-register the provider through the normal UI flow (add custom provider) so the `isCustom` flag is set, instead of hand-editing settings.json.","On settings load, validate that every provider referenced by sessions satisfies one of the two conditions and repair/migrate orphaned entries.","If a builtin provider was removed by an upgrade, remap its id to a current one during migration."],"exampleFix":"// before\nconst model = getModel(session, globals, config, deps)\n// throws 'Cannot find model with provider: x' even though x is in globals\n\n// after: ensure custom provider has the isCustom flag\nconst cp = globals.customProviders?.find(p => p.id === session.provider)\nif (cp && !cp.isCustom) cp.isCustom = true\nconst model = getModel(session, globals, config, deps)","handlingStrategy":"validation","validationCode":"function providerIsResolvable(provider: string, globals: Settings): boolean {\n  if (getProviderDefinition(provider)) return true\n  const cp = (globals.customProviders || []).find(p => p.id === provider)\n  return !!cp && cp.isCustom === true\n}","typeGuard":"function isResolvableProvider(provider: string, globals: Settings): boolean {\n  return getProviderDefinition(provider) !== undefined\n    || (globals.customProviders || []).some(p => p.id === provider && p.isCustom === true)\n}","tryCatchPattern":"try { return getModel(settings, globals, config, deps) }\ncatch (e) {\n  if (e instanceof Error && e.message.startsWith('Cannot find model with provider')) {\n    const cp = (globals.customProviders || []).find(p => p.id === settings.provider)\n    if (cp) cp.isCustom = true  // repair missing flag\n    return getModel(settings, globals, config, deps)\n  }\n  throw e\n}","preventionTips":["Never hand-edit settings.json to add custom providers — use the UI so isCustom is set.","On load, validate that every provider referenced by sessions is resolvable.","Add a registry-vs-customProviders reconciliation step after migrations."],"tags":["configuration","provider","registry","custom-provider","factory","inconsistent-state"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}