chatboxai/chatbox · error · Error

local_parser_file_too_large

local_parser_file_too_large

Error message

local_parser_file_too_large

What it means

Thrown by Claude.listModels() when the GET to `${claudeApiHost}/models?limit=990` returns a JSON body without a top-level `data` array. The whole response is JSON.stringified into the message (and ApiError prefixes it with 'API Error: '). This is a shape-guard: the Anthropic /models endpoint normally returns `{ data: [{ id, type }] }`, so a missing `data` field means the request did not reach a real Anthropic-compatible models endpoint.

Source

Thrown at src/main/file-parser.ts:162

 * which emits "\n\n==== Page %d ====\n\n"). Models see this exact format for PDFs
 * parsed remotely (Web/mobile) and locally (desktop); changing it on one side only
 * makes citations inconsistent across platforms.
 */
function formatPdfPageMarker(pageNumber: number): string {
  return `==== Page ${pageNumber} ====`
}

/**
 * Parse a PDF into plain text with per-page markers (see {@link formatPdfPageMarker})
 * so that models can cite PDF page numbers instead of line numbers of the extracted
 * text.
 */
export async function parsePdf(filePath: string): Promise<string> {
  // Guard before reading the file into memory: pdfjs holds the buffer plus its own
  // internal copy, so a huge PDF can transiently use several times its size.
  const stats = await fs.stat(filePath)
  if (stats.size > LOCAL_PARSER_MAX_PDF_FILE_SIZE) {
    throw new Error(LOCAL_PARSER_FILE_TOO_LARGE_ERROR)
  }
  const { getDocument } = await loadPdfjs()
  const fileBuffer = await fs.readFile(filePath)
  const loadingTask = getDocument({
    data: new Uint8Array(fileBuffer),
    // Text extraction does not render glyphs; pdfjs package assets (cMaps,
    // standard fonts) are not shipped with the bundled main process.
    useSystemFonts: true,
  })
  try {
    const document = await loadingTask.promise
    const pageTexts: string[] = []
    for (let pageNumber = 1; pageNumber <= document.numPages; pageNumber++) {
      try {
        const page = await document.getPage(pageNumber)
        try {
          const textContent = await page.getTextContent()
          let pageText = ''

View on GitHub (pinned to 81571269ad)

Solutions

  1. Verify the API key/OAuth token is valid by sending a chat completion request — if chat works but listModels fails, the host does not implement the Anthropic /models schema.
  2. Check `claudeApiHost`: it must point at a host whose `/models?limit=990` endpoint returns `{ data: [{ id, type: 'model' }] }`. For proxies, confirm they proxy the real Anthropic `/v1/models` route.
  3. Inspect the JSON.stringify'd message in the thrown ApiError — it is the raw upstream body and tells you whether it is an auth error (`type:'error', error.type:'authentication_error'`), overload, or a different-schema response.
  4. If using a proxy that only speaks OpenAI `/v1/models`, switch the provider to a Custom OpenAI provider instead of Claude, or stop calling listModels (supply model IDs manually in settings).

Example fix

// before: host returns OpenAI schema
//   headers set, GET /models -> { models: [...] }, throws ApiError('{"models":[...]}')
// after: point host at Anthropic-compatible /models, or predefine models
const models = settings.claudeApiHost.endsWith('anthropic.com')
  ? await claude.listModels()
  : [{ modelId: 'claude-sonnet-4-5', type: 'chat' }]
Defensive patterns

Strategy: try-catch

Validate before calling

async function safeListClaudeModels(host: string, key: string, token?: string): Promise<boolean> {
  const headers: Record<string,string> = { 'anthropic-version': '2023-06-01' }
  if (token) headers['Authorization'] = `Bearer ${token}`; else headers['x-api-key'] = key
  const res = await fetch(`${host}/v1/models?limit=990`, { headers })
  const json = await res.json().catch(() => ({}))
  return Array.isArray((json as any)?.data)
}

Type guard

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

Try / catch

try {
  const models = await claude.listModels()
} catch (e) {
  if (e instanceof ApiError) {
    console.warn('Claude listModels upstream body:', e.message.replace('API Error: ', ''))
    return []  // fall back to manual model list
  }
  throw e
}

Prevention

When it happens

Trigger: Calling listModels() with an invalid or expired `claudeApiKey`/`authToken` (Anthropic returns `{ type: 'error', error: {...} }`); a `claudeApiHost` pointing to a proxy that does not implement `/models` (returns `{}` or an OpenAI-style `{ models: [...] }`); Anthropic returns an overload/rate-limit JSON (`{ type: 'error', error: { type: 'overloaded_error' } }`); the host already includes `/v1` so the real path becomes `.../v1/v1/messages` style mismatch handled by normalizeClaudeHost incorrectly.

Common situations: User configures a third-party Claude-compatible proxy (e.g. one-api, openrouter-as-anthropic) whose `/models` route returns a different schema; OAuth access token expired and refresh did not run before listing models; key copied with leading/trailing whitespace; region-blocked Anthropic endpoint returning a non-`data` error body; Anthropic 529 overloaded surfaced during the model-refresh call on app start.

Related errors


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