Mintplex-Labs/anything-llm · error
Voyage AI failed to embed: Rate limit reached
Error message
Voyage AI failed to embed: Rate limit reached
What it means
The @langchain VoyageEmbeddings client does not surface Voyage API errors cleanly: when the API rejects the request (most often rate limiting), the client throws the TypeError "Cannot read properties of undefined (reading '0')" while reading the response. VoyageAiEmbedder catches that specific TypeError and rethrows it as an explicit rate-limit error, because an undefined first result almost always means the API returned an error body instead of embeddings.
Solutions
- Wait for the rate-limit window to reset and retry — the call is idempotent for the same input.
- Reduce pressure: upload fewer/smaller documents at once, or pause other jobs sharing the key.
- Check the Voyage AI dashboard for quota usage and upgrade the tier if this recurs.
- Verify VOYAGEAI_API_KEY is valid — auth failures can produce the same underlying TypeError.
Example fix
// before — fire and forget
const vectors = await embedder.embedChunks(chunks);
// after — retry with backoff on the rate-limit error
async function embedWithRetry(embedder, chunks, attempts = 5) {
for (let i = 1; ; i++) {
try {
return await embedder.embedChunks(chunks);
} catch (err) {
if (err.message.includes("Rate limit reached") && i < attempts) {
await new Promise((r) => setTimeout(r, i * 5000));
continue;
}
throw err;
}
}
} Defensive patterns
Strategy: retry
Validate before calling
function estimateVoyageBatches(chunkCount, batchSize = 128) {
return Math.ceil(chunkCount / batchSize);
}
// Before embedding a big document, check you stay inside your plan's RPM:
if (estimateVoyageBatches(chunks.length) > myPlansRequestsPerMinute) {
throw new Error(
"This upload would exceed the Voyage AI rate limit — split it into smaller jobs."
);
} Try / catch
async function embedVoyageWithBackoff(embedder, chunks, maxAttempts = 5) {
for (let i = 1; ; i++) {
try {
return await embedder.embedChunks(chunks);
} catch (err) {
if (err.message.includes("Rate limit reached") && i < maxAttempts) {
await new Promise((r) => setTimeout(r, i * 5_000));
continue;
}
throw err;
}
}
} Prevention
- Chunk uploads so each stays within your Voyage RPM/TPM allowance (batches of 128 count as one request).
- Serialize embedding jobs sharing a key instead of running them concurrently.
- Treat any langchain 'Cannot read properties of undefined' from Voyage as an API-level failure and inspect the raw response.
When it happens
Trigger: Exceeding Voyage AI RPM/TPM limits while embedDocuments() fans textChunks out into batches of 128; free-tier keys embedding a large document; concurrent embedding jobs sharing one key; an invalid/revoked key taking the same undefined-response path.
Common situations: Initial ingestion of a big workspace on voyage-3-lite free tier; parallel document uploads multiplying request count above the plan limit.
Related errors
- Gemini Failed to embed
- GenericOpenAI Failed to embed
- LiteLLM Failed to embed
- Mistral Failed to embed
- No Voyage AI API key was set.
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/66abed9bbf5f8114.
Report an issue: GitHub.
Appendix: source
Thrown at server/utils/EmbeddingEngines/voyageAi/index.js:63
);
// If given an array return the native Array[Array] format since that should be the outcome.
// But if given a single string, we need to flatten it so that we have a 1D array.
return (Array.isArray(textInput) ? result : result.flat()) || [];
}
async embedChunks(textChunks = []) {
try {
const embeddings = await this.voyage.embedDocuments(textChunks);
return embeddings;
} catch (error) {
console.error("Voyage AI Failed to embed:", error);
if (
error.message.includes(
"Cannot read properties of undefined (reading '0')"
)
)
throw new Error("Voyage AI failed to embed: Rate limit reached");
throw error;
}
}
}
module.exports = {
VoyageAiEmbedder,
};
View on GitHub (pinned to 3aec848f28)