{"record":{"id":"d15da87a21a2ddec","repo":"janhq/jan","slug":"failed-to-count-embedding-tokens-e-instanceof-e","errorCode":null,"errorMessage":"Failed to count embedding tokens: ${e instanceof Error ? e.message : String(e)}","messagePattern":"Failed to count embedding tokens: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/vector-db-extension/src/index.ts","lineNumber":227,"sourceCode":"      return await llm.getEmbeddingContextSize()\n    } catch (e) {\n      throw new Error(\n        `Failed to determine embedding context size: ${e instanceof Error ? e.message : String(e)}`\n      )\n    }\n  }\n\n  private async splitChunkToFit(\n    text: string,\n    budget: number,\n    llm: EmbeddingEngine\n  ): Promise<string[]> {\n    if (!text) return []\n    let count: number\n    try {\n      ;[count] = await llm.countEmbeddingTokens([text])\n    } catch (e) {\n      throw new Error(\n        `Failed to count embedding tokens: ${e instanceof Error ? e.message : String(e)}`\n      )\n    }\n    if (count <= budget || text.length <= MIN_CHUNK_SIZE_CHARS) return [text]\n    const mid = Math.floor(text.length / 2)\n    return [\n      ...(await this.splitChunkToFit(text.slice(0, mid), budget, llm)),\n      ...(await this.splitChunkToFit(text.slice(mid), budget, llm)),\n    ]\n  }\n\n  async ingestFile(threadId: string, file: VectorDBFileInput, opts: VectorDBIngestOptions): Promise<AttachmentFileInfo> {\n    // Check for duplicate file (same name + path)\n    const existingFiles = await vecdb.listAttachments(this.collectionForThread(threadId)).catch(() => [])\n    const duplicate = existingFiles.find((f: any) => f.name === file.name && f.path === file.path)\n    if (duplicate) {\n      throw new Error(`File '${file.name}' has already been attached to this thread`)\n    }","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/extensions/vector-db-extension/src/index.ts#L209-L245","documentation":"splitChunkToFit counts tokens per chunk via llm.countEmbeddingTokens(); if that call throws, the error is rewrapped as 'Failed to count embedding tokens' with the original message. Token counting is required to decide whether a chunk fits the embedding context budget, so a failure here aborts chunking.","triggerScenarios":"ensureChunksFitEmbeddingContext or a recursive splitChunkToFit call invokes llm.countEmbeddingTokens([text]) and the embedding engine throws — provider unreachable, auth failure, or a broken/unimplemented tokenizer in the engine.","commonSituations":"Remote embedding API outage or rate limit during ingestion of a large document, invalid provider credentials, or an engine whose countEmbeddingTokens is not supported for the selected model.","solutions":["Read the appended underlying message to find the actual failure (auth, network, unsupported method).","Verify the embedding provider is reachable and credentials are valid.","Retry ingestion after transient network/rate-limit failures resolve.","If the engine cannot count tokens, switch to an engine/model that implements countEmbeddingTokens or estimate tokens heuristically before ingestion."],"exampleFix":"// before\nawait ensureChunksFitEmbeddingContext(llm, text) // throws on provider outage\n// after\ntry {\n  await ensureChunksFitEmbeddingContext(llm, text)\n} catch (e) {\n  if (/Failed to count embedding tokens/.test(String(e))) {\n    await new Promise(r => setTimeout(r, 2000)) // backoff, then retry\n    await ensureChunksFitEmbeddingContext(llm, text)\n  } else throw e\n}","handlingStrategy":"retry","validationCode":"if (typeof llm.countEmbeddingTokens !== 'function') {\n  throw new Error('embedding engine does not implement countEmbeddingTokens')\n}","typeGuard":"function canCountTokens(e: unknown): e is EmbeddingEngine & { countEmbeddingTokens(texts: string[]): Promise<[number]> } {\n  return typeof (e as any)?.countEmbeddingTokens === 'function'\n}","tryCatchPattern":"try {\n  const chunks = await ensureChunksFitEmbeddingContext(llm, text)\n} catch (e) {\n  if (/rate limit|timeout|network/i.test(String(e))) {\n    await backoffRetry(() => ensureChunksFitEmbeddingContext(llm, text), 3)\n  } else throw e\n}","preventionTips":["Prefer local tokenizers or engines with guaranteed countEmbeddingTokens support.","Wrap provider calls with retry/backoff for transient network and rate-limit errors.","Verify credentials and endpoint reachability before batch ingestion of large documents."],"tags":["embedding","tokenization","wrapper-error"],"backgroundTag":"api-request-failed","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}