{"record":{"id":"11ab5ed75d4432a0","repo":"Mintplex-Labs/anything-llm","slug":"openrouter-failed-to-embed-error","errorCode":null,"errorMessage":"OpenRouter Failed to embed: ${error}","messagePattern":"OpenRouter Failed to embed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/EmbeddingEngines/openRouter/index.js","lineNumber":94,"sourceCode":"        .flat();\n      if (errors.length > 0) {\n        let uniqueErrors = new Set();\n        errors.map((error) =>\n          uniqueErrors.add(`[${error.type}]: ${error.message}`)\n        );\n\n        return {\n          data: [],\n          error: Array.from(uniqueErrors).join(\", \"),\n        };\n      }\n      return {\n        data: results.map((res) => res?.data || []).flat(),\n        error: null,\n      };\n    });\n\n    if (!!error) throw new Error(`OpenRouter Failed to embed: ${error}`);\n    return data.length > 0 &&\n      data.every((embd) => embd.hasOwnProperty(\"embedding\"))\n      ? data.map((embd) => embd.embedding)\n      : null;\n  }\n}\n\nasync function fetchOpenRouterEmbeddingModels() {\n  return await fetch(`https://openrouter.ai/api/v1/embeddings/models`, {\n    method: \"GET\",\n    headers: { \"Content-Type\": \"application/json\" },\n  })\n    .then((res) => res.json())\n    .then(({ data = [] }) => {\n      const models = {};\n      data.forEach((model) => {\n        models[model.id] = {\n          id: model.id,","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/utils/EmbeddingEngines/openRouter/index.js#L76-L112","documentation":"The aggregate wrapper thrown at the end of OpenRouterEmbedder.embedChunks() when one or more batched embedding requests to https://openrouter.ai/api/v1/embeddings failed. Distinct error messages are joined after the prefix and partial data is discarded. The suffix usually carries OpenRouter's own status text: 429 rate limit, 401/402 auth or credit issues, 404 unknown model, or upstream provider errors.","triggerScenarios":"Out of OpenRouter credits (402); 429 when embedding a large document quickly; EMBEDDING_MODEL_PREF set to a model that is not an OpenRouter embedding model (404/no endpoints); the key was revoked; upstream provider outages surfaced through OpenRouter.","commonSituations":"First big workspace sync on a new OpenRouter account; switching EMBEDDING_MODEL_PREF to a chat model id; free-tier keys hitting RPM limits.","solutions":["Read the suffix — it is OpenRouter's literal error message and determines the fix.","On 402/401: add credit or refresh OPENROUTER_API_KEY.","On 404/model errors: pick a model from OpenRouter's /api/v1/embeddings/models list (e.g. baai/bge-m3).","On 429: slow down ingestion and retry; embedding requests count against the same limits as chat."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function embedWithRetry(embedder, chunks, maxAttempts = 4) {\n  for (let i = 1; ; i++) {\n    try {\n      return await embedder.embedChunks(chunks);\n    } catch (err) {\n      const msg = err.message;\n      const transient = msg.includes(\"429\") || msg.includes(\"Rate limit\");\n      if (transient && i < maxAttempts) {\n        await new Promise((r) => setTimeout(r, i * 10_000));\n        continue;\n      }\n      throw err; // 401/402 (auth/credit) and 404 (model) are not retryable\n    }\n  }\n}","preventionTips":["Confirm EMBEDDING_MODEL_PREF appears in OpenRouter's /api/v1/embeddings/models list.","Keep OpenRouter credit topped up before bulk ingestion.","Classify by the error suffix before retrying."],"tags":["openrouter","embeddings","rate-limit","wrapped-error"],"backgroundTag":"upstream-request-failed","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}