Mintplex-Labs/anything-llm · error · Error

Mistral Failed to embed: ${error.message}

Error message

Mistral Failed to embed: ${error.message}

What it means

Thrown in the embedChunks catch block wrapping the entire embeddings.create call. Any rejection — network error, non-2xx HTTP, the explicit 'empty embeddings' throw above, or an SDK parse failure — is caught, logged to console.error, and re-thrown as 'Mistral Failed to embed: <original message>'. It is the single escape hatch for all Mistral embedding failures.

Source

Thrown at server/utils/EmbeddingEngines/mistral/index.js:34

      Array.isArray(textInput) ? textInput : [textInput]
    );
    return result?.[0] || [];
  }

  async embedChunks(textChunks = []) {
    try {
      const response = await this.openai.embeddings.create({
        model: this.model,
        input: textChunks,
        encoding_format: "float",
      });
      const embeddings = response?.data?.map((emb) => emb.embedding) || [];
      if (embeddings.length === 0)
        throw new Error("Mistral returned empty embeddings for batch");
      return embeddings;
    } catch (error) {
      console.error("Failed to get embeddings from Mistral.", error.message);
      throw new Error(`Mistral Failed to embed: ${error.message}`);
    }
  }
}

module.exports = {
  MistralEmbedder,
};

View on GitHub (pinned to 526360e320)

Solutions

  1. Read error.message in the thrown string: 401 -> rotate/fix MISTRAL_API_KEY; 429 -> reduce batch size / add backoff; 5xx -> retry after a short delay
  2. If the message is 'empty embeddings for batch', follow error 330 fixes (check EMBEDDING_MODEL_PREF is an embedding model)
  3. curl api.mistral.ai/v1/embeddings directly to isolate SDK vs network vs provider
  4. Add retry with exponential backoff in the caller for transient 5xx/429

Example fix

// before
// caller does no retry, single 429 aborts the whole doc ingest

// after
// wrap the embed call with a bounded retry on transient errors
for (let attempt = 0; attempt < 3; attempt++) {
  try { return await embedder.embedChunks(chunks); }
  catch (e) {
    if (attempt === 2 || /401|empty embeddings/.test(e.message)) throw e;
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: key valid and not rate-limited on a tiny call
async function mistralReachable(openai, model) {
  await openai.embeddings.create({ model, input: 'ping' });
}

Type guard

function isMistralEmbedError(e) {
  return e instanceof Error && /Mistral Failed to embed/.test(e.message);
}

Try / catch

async function embedWithRetry(embedder, chunks, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try { return await embedder.embedChunks(chunks); }
    catch (e) {
      const transient = /429|5\d\d|Failed to fetch|ETIMEDOUT/.test(e.message);
      if (!transient || i === attempts - 1) throw e;
      await new Promise(r => setTimeout(r, 2 ** i * 1000));
    }
  }
}

Prevention

When it happens

Trigger: embeddings.create rejects: 401 (bad/expired MISTRAL_API_KEY); 429 rate limit; 5xx Mistral outage; the inner 'Mistral returned empty embeddings for batch' throw; network timeout; SDK unable to parse a non-JSON gateway response.

Common situations: Key expired or revoked; hitting Mistral rate limits on a large batch; transient 5xx; running behind a corporate proxy that returns an HTML error page; deprecated model returning an API error.

Related errors


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