googleapis/mcp-toolbox · error

error unmarshalling projection: %s

Error message

error unmarshalling projection: %s

What it means

After the project payload template renders, the result is parsed as MongoDB Extended JSON via bson.UnmarshalExtJSON. If the rendered string is not valid Extended JSON, the tool wraps the failure as 'error unmarshalling projection'. The template rendered fine, but its output is not a valid projection document.

Source

Thrown at internal/tools/mongodb/mongodbfind/mongodbfind.go:162

	sort := bson.M{}
	for _, p := range sortParameters {
		sort[p.GetName()] = paramsMap[p.GetName()]
	}
	opts = opts.SetSort(sort)

	if len(projectPayload) > 0 {

		result, err := parameters.PopulateTemplateWithJSON("MongoDBFindProjectString", projectPayload, paramsMap)

		if err != nil {
			return nil, fmt.Errorf("error populating project payload: %s", err)
		}

		var projection any
		err = bson.UnmarshalExtJSON([]byte(result), false, &projection)
		if err != nil {
			return nil, fmt.Errorf("error unmarshalling projection: %s", err)
		}

		opts = opts.SetProjection(projection)
		logger.DebugContext(ctx, fmt.Sprintf("Projection is set to %v", projection))
	}

	if limit > 0 {
		opts = opts.SetLimit(limit)
		logger.DebugContext(ctx, fmt.Sprintf("Limit is being set to %d", limit))
	}
	return opts, nil
}

func (t Tool) Invoke(ctx context.Context, s sources.Source, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
	source, ok := s.(compatibleSource)
	if !ok {
		return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, nil)
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Correct the projection JSON in the tool config to valid Extended JSON (e.g. {"name": 1}).
  2. If injecting values via template, ensure they serialize as JSON primitives.
  3. Test the rendered output of the template for validity before use.

Example fix

# before
project: '{ name: 1, created_at: $date }'
# after
project: '{ "name": 1, "created_at": { "$date": "{{.params.start}}" } }'
Defensive patterns

Strategy: validation

Validate before calling

// Go: pre-validate rendered projection parses
var probe any
if err := bson.UnmarshalExtJSON([]byte(rendered), false, &probe); err != nil {
    return fmt.Errorf("invalid projection JSON: %w", err)
}

Try / catch

opts, err := getOptions(ctx, sortParams, projectPayload, limit, paramsMap)
if err != nil && strings.Contains(err.Error(), "error unmarshalling projection") {
    // fall back to no projection
    opts, err = getOptions(ctx, sortParams, "", limit, paramsMap)
}

Prevention

When it happens

Trigger: Invoke() with a project payload whose rendered output is invalid Extended JSON — e.g. unquoted keys produced by the template, wrong value types, or stray text after rendering.

Common situations: Using standard JSON with unquoted keys expecting Extended JSON acceptance is fine, but using shell-style Mongo syntax like {name: 1} with invalid characters; template injecting non-JSON values (dates, ObjectIds as strings) incorrectly; missing $-operator prefix typos.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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