chatboxai/chatbox · error · Error

Failed to search knowledge base (id: ${kbId}). Please try ag

Error message

Failed to search knowledge base (id: ${kbId}). Please try again later.

What it means

Thrown by Gemini.listModels() (built-in Google Gemini provider) when GET `${geminiAPIHost}/v1beta/models?key=...` returns a body without a top-level `models` array. Unlike the custom variant, this method is NOT wrapped in a swallowing try/catch, so the ApiError propagates to the caller. Google's ListModels response is `{ models: [...] }`; anything else is an error envelope (auth/quota) or a misrouted response.

Source

Thrown at src/main/knowledge-base/file-loaders.ts:473

      }
      return results.map((r) => ({
        id: r.id,
        score: r.score,
        ...r.metadata,
      }))
    }
  } catch (e) {
    log.error(`[FILE] Failed to search: kbId=${kbId}, queryLength=${query.length}`, e)

    sentry.withScope((scope) => {
      scope.setTag('component', 'knowledge-base-file')
      scope.setTag('operation', 'search_knowledge_base')
      scope.setExtra('kbId', kbId)
      scope.setExtra('queryLength', query.length)
      sentry.captureException(e)
    })

    throw new Error(`Failed to search knowledge base (id: ${kbId}). Please try again later.`)
  }
}

// Read chunks from vector store
export async function readChunks(kbId: number, chunks: { fileId: number; chunkIndex: number }[]) {
  try {
    log.debug(`[FILE] Reading chunks: kbId=${kbId}, chunks=${chunks.length}`)

    if (!chunks || chunks.length === 0) {
      return []
    }

    const indexName = `kb_${kbId}`
    const results: any[] = []

    // Use single SQL query to get all chunks at once
    log.debug(`[FILE] Using single SQL query via vectorStore.turso for ${chunks.length} chunks`)

View on GitHub (pinned to 81571269ad)

Solutions

  1. Inspect the JSON.stringify'd payload — Google's `{ error: { code, message, status } }` tells you auth (`UNAUTHENTICATED`), quota (`RESOURCE_EXHAUSTED`), or permission denied.
  2. Set `geminiAPIHost` to the base origin (e.g. `https://generativelanguage.googleapis.com`) — do not include `/v1beta`.
  3. Enable the 'Generative Language API' in the Google Cloud project that owns the key and remove referrer/IP restrictions for desktop usage.
  4. Wrap the listModels call in try/catch and fall back to a hardcoded model list so a transient listing failure does not block chat.

Example fix

// before
const models = await gemini.listModels()  // propagates ApiError

// after
try {
  const models = await gemini.listModels()
} catch (e) {
  console.warn('Gemini listModels failed, using fallback', e)
  return [{ modelId: 'gemini-2.5-flash', type: 'chat' }]
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function probeGeminiModels(host: string, key: string): Promise<boolean> {
  const res = await fetch(`${host}/v1beta/models?key=${encodeURIComponent(key)}`)
  const json = await res.json().catch(() => ({}))
  return Array.isArray((json as any)?.models)
}

Type guard

function isGeminiModelsResponse(json: unknown): json is { models: { name: string; supportedGenerationMethods: string[]; inputTokenLimit: number; outputTokenLimit: number; displayName: string }[] } {
  return typeof json === 'object' && json !== null && Array.isArray((json as any).models)
}

Try / catch

try { return await gemini.listModels() }
catch (e) {
  if (e instanceof ApiError) { console.warn('Gemini listModels body:', e.message); return [] }
  throw e
}

Prevention

When it happens

Trigger: Invalid or missing `geminiAPIKey` (Google returns `{ error: { code, message, status } }`); `geminiAPIHost` set to a value that already contains `/v1beta` (URL becomes `.../v1beta/v1beta/models`); the key is restricted to an API that does not include the Generative Language API; a proxy strips the `?key=` query string; region blocks the endpoint and a CDN returns an HTML/JSON error that parses without `models`.

Common situations: API key generated under a Google project where the Generative Language API is disabled; key with HTTP-referrer or IP restriction; user set a custom `geminiAPIHost` that includes a version path; corporate proxy returning a JSON error block; free-tier quota exceeded so the API returns an error object instead of the model list.

Related errors


AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12). Data as JSON: /api/errors/f44035bd152df418. Report an issue: GitHub.