googleapis/mcp-toolbox · error

model %s returned %d embeddings for %d inputs

Error message

model %s returned %d embeddings for %d inputs

What it means

This sanity check fires when the embedding model returns a different number of vectors than the number of input strings sent. The library requires a strict 1:1 mapping to attach each vector back to its parameter. It almost always indicates a bug or contract violation in the embedding model implementation, not in caller code.

Source

Thrown at internal/util/parameters/parameters.go:224

	for modelName, params := range parametersToEmbed {
		model, ok := pMgr.GetEmbeddingModel(modelName)
		if !ok {
			return nil, fmt.Errorf("embedding model does not exist: %s", modelName)
		}

		// Extract only the string values for the API call
		stringBatch := make([]string, len(params))
		for i, paramStr := range params {
			stringBatch[i] = paramStr.OriginalValue
		}

		embeddings, err := model.EmbedParameters(ctx, stringBatch)
		if err != nil {
			return nil, fmt.Errorf("error embedding parameters with model %s: %w", modelName, err)
		}

		if len(embeddings) != len(stringBatch) {
			return nil, fmt.Errorf("model %s returned %d embeddings for %d inputs", modelName, len(embeddings), len(stringBatch))
		}

		for i, rawVector := range embeddings {

			item := params[i]

			// Call vector formatter
			var finalValue any = rawVector

			if formatter == nil {
				paramValues[item.Index].Value = finalValue
				continue
			}

			formattedVector := formatter(rawVector)
			finalValue = formattedVector
			paramValues[item.Index].Value = finalValue
		}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Fix the model's EmbedParameters implementation so it returns exactly one embedding per input or a non-nil error.
  2. Log the raw provider response to identify which inputs were dropped (e.g. content filtering, empty strings).
  3. In a paginating wrapper, concatenate every page's results before returning.
  4. Handle empty or filtered inputs explicitly with a placeholder vector or an error so the result count is preserved.

Example fix

// before: drops failed inputs, breaking 1:1 mapping
out := []vector{}
for _, b := range batch {
    v, err := embedOne(b)
    if err != nil { continue }
    out = append(out, v)
}

// after: error instead of shrinking the result
out := make([]vector, 0, len(batch))
for _, b := range batch {
    v, err := embedOne(b)
    if err != nil { return nil, err }
    out = append(out, v)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if got := len(embeddings); got != len(batch) {
    return fmt.Errorf("model returned %d embeddings for %d inputs", got, len(batch))
}

Type guard

func embeddingsMatchInputs(embeds []Embedding, inputs []string) bool {
    return len(embeds) == len(inputs)
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "returned") && strings.Contains(err.Error(), "embeddings") {
        // log inputs, flag model implementation bug, skip cache write
    }
    return err
}

Prevention

When it happens

Trigger: model.EmbedParameters returns a slice whose length differs from len(stringBatch): a custom model implementation silently dropping failed inputs, truncating batches, paginating without concatenating pages, or the provider omitting embeddings for content-filtered inputs.

Common situations: Custom or third-party embedding model wrappers that skip failed items instead of erroring; provider content filtering on some inputs; batch pagination bugs; implementations that deduplicate identical input strings.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/429c6d53786b1e4f. Report an issue: GitHub.