googleapis/mcp-toolbox · error
header param %s got value of type %t, not string
Error message
header param %s got value of type %t, not string
What it means
HTTP header parameters must be supplied as JSON/YAML strings. getHeaders iterates the declared header parameters and errors when a provided value exists but is not a string (e.g. a number, boolean, object, or array), since HTTP header values must be text.
Source
Thrown at internal/tools/http/http.go:264
}
query.Add(p.GetName(), fmt.Sprintf("%v", v))
}
parsedURL.RawQuery = query.Encode()
return parsedURL.String(), nil
}
// Helper function to generate the HTTP headers upon Tool invocation.
func getHeaders(headerParams parameters.Parameters, defaultHeaders map[string]string, paramsMap map[string]any) (map[string]string, error) {
// Populate header params
allHeaders := make(map[string]string)
maps.Copy(allHeaders, defaultHeaders)
for _, p := range headerParams {
headerValue, ok := paramsMap[p.GetName()]
if ok {
if strValue, ok := headerValue.(string); ok {
allHeaders[p.GetName()] = strValue
} else {
return nil, fmt.Errorf("header param %s got value of type %t, not string", p.GetName(), headerValue)
}
}
}
return allHeaders, 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)
}
// Combine Source and Tool headers.
// In case of conflict, Tool header overrides Source header
combinedHeaders := make(map[string]string)
maps.Copy(combinedHeaders, source.HttpDefaultHeaders())
maps.Copy(combinedHeaders, t.Cfg.Headers)
paramsMap := params.AsMap()View on GitHub (pinned to 8cc6e09de2)
Solutions
- Convert the value to a string before invoking (e.g. "5", "true", "12345")
- Quote the value in YAML tool configs so it parses as a string
- If the value comes from an LLM/model call, add instructions or schema constraints so header params are always emitted as strings
Example fix
// before
{"headers": {"X-Count": 5}}
// after
{"headers": {"X-Count": "5"}} Defensive patterns
Strategy: type-guard
Validate before calling
for k, v := range headerArgs {
if _, ok := v.(string); !ok {
return fmt.Errorf("header %s must be a string, got %T", k, v)
}
} Type guard
func allStrings(m map[string]any) bool {
for _, v := range m {
if _, ok := v.(string); !ok { return false }
}
return true
} Try / catch
headers, err := tool.Invoke(ctx, params)
if err != nil && strings.Contains(err.Error(), "got value of type") {
// coerce values to strings and retry once
}
var typeErr *json.UnmarshalTypeError // if parsing client-side, check this Prevention
- Quote numeric/boolean header values in YAML configs and JSON payloads
- Declare header parameters with string-typed schemas so clients coerce automatically
- Instruct LLM callers that header parameters must be strings
When it happens
Trigger: Invoke is called with a header parameter set to a non-string JSON value, e.g. {"X-Count": 5} or {"X-Flag": true} or a nested object, for a parameter declared in headerParams.
Common situations: LLM tool callers emitting unquoted numbers/booleans for headers; clients passing integers for numeric-looking headers like X-Request-Id: 12345; YAML configs with unquoted values that parse as bool/int.
Related errors
- 'filter_expression' must be a string, got %T
- error getting parameters for tool: %w
- invalid parameters: %w
- error embedding parameters: %w
- failed to fetch OIDC config: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/9d71a4bebccad4e4.
Report an issue: GitHub.