chatboxai/chatbox · error · Error

No content extracted from file

Error message

No content extracted from file

What it means

Thrown by DeepSeek.listModels() when GET `https://api.deepseek.com/models` (hardcoded host) returns a body without a `data` field. DeepSeek's OpenAI-compatible API returns `{ data: [{ id, owned_by }] }`, so a missing `data` field means the request was rejected (auth/billing) or the hardcoded URL was redirected to a non-API response. The whole body is JSON.stringified into the message.

Source

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

    })

    // 2. Chunking
    const allChunks = await doc.chunk({
      strategy: 'recursive',
      maxSize: 1200,
      overlap: 150,
    })

    if (!allChunks || allChunks.length === 0) {
      // Cloud parsing (chatbox-ai, mineru) resulted in 0 chunks - mark as done (truly empty file)
      // Local parsing resulted in 0 chunks - mark as failed so user can retry with server parsing
      if (parserConfig.type === 'chatbox-ai' || parserConfig.type === 'mineru') {
        await db.execute({
          sql: 'UPDATE kb_file SET chunk_count = 0, status = ? WHERE id = ?',
          args: ['done', fileMeta.fileId],
        })
      } else {
        throw new Error('No content extracted from file')
      }
      return
    }

    // Record total chunks if not already recorded
    if (currentTotalChunks === 0 || currentTotalChunks !== allChunks.length) {
      await db.execute({
        sql: 'UPDATE kb_file SET total_chunks = ? WHERE id = ?',
        args: [allChunks.length, fileMeta.fileId],
      })
      log.debug(`[FILE] Recorded total chunks: ${allChunks.length} for file ${fileMeta.fileId}`)
    }

    log.debug(`[FILE] Processing progress: ${currentChunkCount}/${allChunks.length} chunks already processed`)

    // 3. Check if processing is already complete
    if (currentChunkCount >= allChunks.length) {
      log.info(`[FILE] File already fully processed: ${fileMeta.filename} (id=${fileMeta.fileId})`)

View on GitHub (pinned to 81571269ad)

Solutions

  1. Read the JSON.stringify'd body in the ApiError message — DeepSeek's `{ error: { message: '...' } }` tells you whether it is auth, balance, or rate limit.
  2. Top up DeepSeek balance and confirm the key is valid at platform.deepseek.com; verify the key has no leading/trailing space.
  3. Check network egress: api.deepseek.com must be reachable and not rewritten by a proxy/captive portal.
  4. If the host must be configurable, note this provider hardcodes the URL — switch to a Custom OpenAI provider pointing at DeepSeek so you can set apiHost and use a listModels path that your relay supports.

Example fix

// before
const json = await res.json()
if (!json.data) throw new ApiError(JSON.stringify(json))

// after: surface the upstream error message
if (!json.data) {
  const msg = json?.error?.message || JSON.stringify(json)
  throw new ApiError(`DeepSeek listModels failed: ${msg}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function probeDeepSeek(key: string): Promise<boolean> {
  const res = await fetch('https://api.deepseek.com/models', { headers: { Authorization: `Bearer ${key}` } })
  const json = await res.json().catch(() => ({}))
  return Array.isArray((json as any)?.data)
}

Type guard

function isDeepSeekModelsResponse(json: unknown): json is { data: { id: string; owned_by?: string }[] } {
  return typeof json === 'object' && json !== null && Array.isArray((json as any).data)
}

Try / catch

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

Prevention

When it happens

Trigger: Invalid or empty `apiKey` (DeepSeek returns `{ error: {...} }` with 401 but the body still parses without `data`); account has no balance / billing disabled (DeepSeek returns an error object); a transparent proxy or captive portal returns HTML that res.json() parses to `{}`; DeepSeek API is temporarily down and returns a JSON error envelope; the URL is intercepted by a custom DNS/firewall returning a different schema.

Common situations: New key not yet activated; key pasted with surrounding whitespace; free trial credit exhausted so the API rejects listing; running behind a corporate proxy that rewrites api.deepseek.com to an internal stub; user in a region where the endpoint is blocked and a CDN returns an error JSON.

Related errors


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