rohitg00/agentmemory · error · Error

Voyage embedding failed (${response.status}): ${err}

Error message

Voyage embedding failed (${response.status}): ${err}

What it means

The Voyage AI embeddings API (POST /v1/embeddings with input_type) returned a non-2xx status. embedBatch captures the response body and throws it with the status code, exposing Voyage-side validation, auth, or quota failures.

Source

Thrown at src/providers/embedding/voyage.ts:38

  }

  async embedBatch(texts: string[]): Promise<Float32Array[]> {
    const response = await fetchWithTimeout(API_URL, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${this.apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "voyage-code-3",
        input: texts,
        input_type: "document",
      }),
    });

    if (!response.ok) {
      const err = await response.text();
      throw new Error(`Voyage embedding failed (${response.status}): ${err}`);
    }

    const data = (await response.json()) as {
      data: Array<{ embedding: number[] }>;
    };

    return data.data.map((d) => new Float32Array(d.embedding));
  }
}

View on GitHub (pinned to e04ba88819)

Solutions

  1. Read the status: 401 -> fix key; 400 -> check model id and input length; 429 -> back off and shrink batches
  2. Split large texts/batches to respect Voyage token and rate limits
  3. Confirm no proxy/interceptor removes the Authorization header
  4. Add retry with backoff for 429/5xx
  5. Fall back to another provider via createFallbackProvider for resilience

Example fix

// before
await provider.embedBatch([veryLongDoc]); // 400: exceeds token limit
// after
const chunks = splitByTokens(veryLongDoc, 4000);
const vectors = await provider.embedBatch(chunks);
Defensive patterns

Strategy: retry

Validate before calling

const MAX_TOKENS = 4000;
const safeTexts = texts.map(t => t.length > 16000 ? truncate(t) : t); // coarse guard
if (safeTexts.length === 0) throw new Error('embedBatch called with empty input');

Type guard

const isVoyageHttpError = (err: unknown): err is Error & { status?: number } => {
  const m = String((err as Error)?.message).match(/Voyage embedding failed \((\d+)\)/);
  return !!m && ((err as Error).status = Number(m[1]), true);
};

Try / catch

try {
  return await provider.embedBatch(texts);
} catch (err) {
  if (isVoyageHttpError(err)) {
    if (err.status === 429 || err.status >= 500) return withBackoff(() => provider.embedBatch(texts));
    if (err.status === 400) return provider.embedBatch(texts.map(chunkText));
    if (err.status === 401) throw new Error('Fix VOYAGE_API_KEY');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling embed()/embedBatch() when Voyage rejects the request: 401 invalid VOYAGE_API_KEY, 400 invalid model or input exceeding token limits, 429 rate limit, 5xx outage.

Common situations: Free-tier quota exhausted during bulk backfill; model id typo (voyage-3 vs voyage-2); oversized batch or single text above the token cap; corporate proxy stripping the Authorization header.

Related errors


AI-assisted analysis of rohitg00/agentmemory@e04ba88819 (2026-08-30). Data as JSON: /api/errors/db452724a0536940. Report an issue: GitHub.