Mintplex-Labs/anything-llm · error · Error

OpenRouter Failed to embed: ${error}

Error message

OpenRouter Failed to embed: ${error}

What it means

Thrown at the end of OpenRouterEmbedder.embedChunks after all parallel embedding batches settle. Each batch runs as a self-catching Promise that resolves with {data:[], error} on failure instead of rejecting, so Promise.all never rejects. The collected unique errors are joined into one string and thrown here only if at least one batch failed. The wrapped error string is already formatted like '[429]: <message>' because the per-batch catch normalizes e.type and e.message from the OpenAI SDK response shape.

Source

Thrown at server/utils/EmbeddingEngines/openRouter/index.js:94

        .flat();
      if (errors.length > 0) {
        let uniqueErrors = new Set();
        errors.map((error) =>
          uniqueErrors.add(`[${error.type}]: ${error.message}`)
        );

        return {
          data: [],
          error: Array.from(uniqueErrors).join(", "),
        };
      }
      return {
        data: results.map((res) => res?.data || []).flat(),
        error: null,
      };
    });

    if (!!error) throw new Error(`OpenRouter Failed to embed: ${error}`);
    return data.length > 0 &&
      data.every((embd) => embd.hasOwnProperty("embedding"))
      ? data.map((embd) => embd.embedding)
      : null;
  }
}

async function fetchOpenRouterEmbeddingModels() {
  return await fetch(`https://openrouter.ai/api/v1/embeddings/models`, {
    method: "GET",
    headers: { "Content-Type": "application/json" },
  })
    .then((res) => res.json())
    .then(({ data = [] }) => {
      const models = {};
      data.forEach((model) => {
        models[model.id] = {
          id: model.id,

View on GitHub (pinned to 526360e320)

Solutions

  1. Check the wrapped error string — the [type] prefix identifies the cause: [429] = rate limit (wait and retry / upgrade tier), [401] = bad key, [failed_to_embed] = network/model issue.
  2. Verify OPENROUTER_API_KEY is set and valid by calling the OpenRouter embeddings models endpoint directly.
  3. Confirm EMBEDDING_MODEL_PREF is a valid OpenRouter embedding model id (list via fetchOpenRouterEmbeddingModels).
  4. For 429s, reduce workspace embed batch size or add delay/backoff; OpenRouter free tier has strict RPM limits.
  5. Ensure no single input chunk exceeds 8191 tokens (the embeddingMaxChunkLength) — pre-split oversized chunks before embedding.

Example fix

// before: oversized chunks cause model rejection
await openRouterEmbedder.embedChunks(hugeDocumentChunks);

// after: pre-split chunks under the token limit before embedding
const MAX_TOKENS = 8000; // stay below 8191
const safeChunks = hugeDocumentChunks.flatMap(c => splitIfTooLong(c, MAX_TOKENS));
await openRouterEmbedder.embedChunks(safeChunks);
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate model and key before embedding
const { fetchOpenRouterEmbeddingModels } = require("./openRouter");
const models = await fetchOpenRouterEmbeddingModels();
if (!models[process.env.EMBEDDING_MODEL_PREF]) {
  throw new Error(`Unknown OpenRouter embedding model: ${process.env.EMBEDDING_MODEL_PREF}`);
}
if (!process.env.OPENROUTER_API_KEY) {
  throw new Error('OPENROUTER_API_KEY is not set');
}

Type guard

/** @param {unknown} e */
function isOpenRouterEmbedError(e) {
  return e instanceof Error && /^OpenRouter Failed to embed:/.test(e.message);
}

Try / catch

try {
  const vectors = await embedder.embedChunks(chunks);
  if (!vectors) throw new Error('Embedding produced no vectors');
} catch (e) {
  if (/\[429\]/.test(e.message)) { /* backoff and retry */ }
  else if (/\[401\]|\[403\]/.test(e.message)) throw new Error('Bad OpenRouter API key');
  else throw e;
}

Prevention

When it happens

Trigger: Calling embedChunks/embedTextInput with an invalid or unset OPENROUTER_API_KEY, a non-existent EMBEDDING_MODEL_PREF, input text exceeding the 8191-token embeddingMaxChunkLength per chunk, OpenRouter HTTP rate limits (429), upstream provider outages, or network failures during the embeddings.create call. Because batches of up to maxConcurrentChunks (500) are fired in parallel, a single failing batch aborts the whole sequence.

Common situations: Switching embedding models without updating EMBEDDING_MODEL_PREF to a valid OpenRouter embedding model id; hitting OpenRouter free-tier rate limits when embedding a large workspace; passing oversized document chunks that exceed the model context window; API key rotated in the provider but not in the AnythingLLM env; transient OpenRouter routing errors to the backing model provider.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/11ab5ed75d4432a0. Report an issue: GitHub.