googleapis/mcp-toolbox · error

invalid '%s' parameter; expected a string array

Error message

invalid '%s' parameter; expected a string array

What it means

ParseDICOMSearchParameters expects the `includefield` parameter to arrive as an array (JSON array of attribute IDs). If the value is any other JSON type (string, number, object), the type assertion to []any fails and this error is returned.

Source

Thrown at internal/tools/cloudhealthcare/common/util.go:66

	if !ok {
		return "", fmt.Errorf("invalid or missing '%s' parameter; expected a string", StoreKey)
	}
	if len(allowedStores) > 0 {
		if _, ok := allowedStores[storeID]; !ok {
			return "", fmt.Errorf("store ID '%s' is not in the list of allowed stores", storeID)
		}
	}
	return storeID, nil
}

// ParseDICOMSearchParameters extracts the search parameters for various DICOM
// search methods.
func ParseDICOMSearchParameters(params parameters.ParamValues, paramKeys []string) ([]googleapi.CallOption, error) {
	var opts []googleapi.CallOption
	for k, v := range params.AsMap() {
		if k == IncludeAttributesKey {
			if _, ok := v.([]any); !ok {
				return nil, fmt.Errorf("invalid '%s' parameter; expected a string array", k)
			}
			attributeIDsSlice, err := parameters.ConvertAnySliceToTyped(v.([]any), "string")
			if err != nil {
				return nil, fmt.Errorf("can't convert '%s' to array of strings: %s", k, err)
			}
			attributeIDs := attributeIDsSlice.([]string)
			if len(attributeIDs) != 0 {
				opts = append(opts, googleapi.QueryParameter(k, strings.Join(attributeIDs, ",")))
			}
		} else if k == EnablePatientNameFuzzyMatchingKey {
			if _, ok := v.(bool); !ok {
				return nil, fmt.Errorf("invalid '%s' parameter; expected a boolean", k)
			}
			opts = append(opts, googleapi.QueryParameter(k, fmt.Sprintf("%t", v.(bool))))
		} else if slices.Contains(paramKeys, k) {
			if _, ok := v.(string); !ok {
				return nil, fmt.Errorf("invalid '%s' parameter; expected a string", k)
			}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Send `includefield` as a JSON array of strings, e.g. ["00100010"].
  2. If you have a single value, wrap it: ["<value>"].
  3. Validate the payload shape before invoking the tool.
  4. Split any comma-separated string into elements client-side before sending.

Example fix

// before
{"includefield": "00100010,00100020"}
// after
{"includefield": ["00100010", "00100020"]}
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizeIncludeField(v) {
  if (typeof v === 'string') v = v.split(',').map(s => s.trim()).filter(Boolean);
  if (!Array.isArray(v) || !v.every(x => typeof x === 'string')) {
    throw new Error('includefield must be an array of strings');
  }
  return v;
}

Type guard

function isStringArray(v) { return Array.isArray(v) && v.every(x => typeof x === 'string'); }

Prevention

When it happens

Trigger: Invoking a DICOM search tool with `includefield` supplied as a plain string (e.g. "00100010") or a number instead of an array like ["00100010"].

Common situations: LLM passing a comma-separated string instead of a JSON array; hand-written HTTP clients forgetting the array wrapper; schema drift where the client sends the old singular field.

Related errors


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