weaviate/weaviate · error

connection to VoyageAI API failed with status %d

Error message

connection to VoyageAI API failed with status %d

What it means

The VoyageAI rerank API returned a non-2xx HTTP status but the response body either failed to parse as an error object or had an empty `message` field, so Weaviate reports only the status code. It indicates an upstream rejection whose details were not exposed in the expected format.

Source

Thrown at modules/reranker-voyageai/clients/ranker.go:148

		return nil, errors.Wrap(err, "send POST request")
	}
	defer res.Body.Close()

	bodyBytes, err := io.ReadAll(res.Body)
	if err != nil {
		return nil, errors.Wrap(err, "read response body")
	}

	if res.StatusCode != 200 {
		var apiError voyageAiApiError
		err = json.Unmarshal(bodyBytes, &apiError)
		if err != nil {
			return nil, errors.Wrap(err, "unmarshal error from response body")
		}
		if apiError.Message != "" {
			return nil, errors.Errorf("connection to VoyageAI API failed with status %d: %s", res.StatusCode, apiError.Message)
		}
		return nil, errors.Errorf("connection to VoyageAI API failed with status %d", res.StatusCode)
	}

	var rankResponse RankResponse
	if err := json.Unmarshal(bodyBytes, &rankResponse); err != nil {
		return nil, fmt.Errorf("failed to parse reranker response (status %d): %w", res.StatusCode, err)
	}
	return c.toDocumentScores(documents, rankResponse.Data), nil
}

func (c *client) chunkDocuments(documents []string, chunkSize int) [][]string {
	var requests [][]string
	for i := 0; i < len(documents); i += chunkSize {
		end := i + chunkSize

		if end > len(documents) {
			end = len(documents)
		}

View on GitHub (pinned to 75aa4b6d11)

Solutions

  1. Check VoyageAI service status for incidents causing bare 5xx responses
  2. Inspect any proxy/load balancer between Weaviate and the internet that may strip or replace response bodies
  3. Validate the configured API key and model with a direct curl call to see the real status
  4. Retry with backoff for 429/5xx; fix credentials for 401/403
Defensive patterns

Strategy: retry

Validate before calling

func preflightVoyageai(ctx context.Context, apiKey string) error {
  if apiKey == "" { return errors.New("VOYAGEAI_APIKEY is not set") }
  req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.voyageai.com/v1/models", nil)
  req.Header.Set("Authorization", "Bearer "+apiKey)
  res, err := http.DefaultClient.Do(req)
  if err != nil { return err }
  defer res.Body.Close()
  io.Copy(io.Discard, res.Body)
  if res.StatusCode >= 400 { return fmt.Errorf("voyageai preflight failed: %d", res.StatusCode) }
  return nil
}

Try / catch

results, err := voyageClient.Rank(ctx, query, docs)
if err != nil {
  if isRetryable(err) { // 429/5xx per the status text
    return withBackoff(func() error { _, err = voyageClient.Rank(ctx, query, docs); return err })
  }
  return fmt.Errorf("rerank failed without upstream detail: %w", err)
}

Prevention

When it happens

Trigger: performRank received e.g. 401/429/500 from api.voyageai.com with an empty body, an HTML error page (proxy/gateway), or a JSON body lacking the `message` field.

Common situations: Corporate proxies or API gateways returning HTML error pages; VoyageAI returning empty-bodied 5xx during incidents; rate-limit responses without a JSON message.

Related errors


AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04). Data as JSON: /api/errors/cd2d2386781da766. Report an issue: GitHub.