googleapis/mcp-toolbox · error
cannot unmarshal %T into StringOrStringSlice
Error message
cannot unmarshal %T into StringOrStringSlice
What it means
This error comes from the custom UnmarshalYAML implementation of the StringOrStringSlice type in the BigQuery source config. StringOrStringSlice accepts either a single YAML string or a sequence of strings; if the YAML value is neither (e.g. a number, boolean, map, or a sequence containing non-strings), the unmarshaller returns this error. It is thrown at config-parse time before any connection is made.
Source
Thrown at internal/sources/bigquery/bigquery.go:131
var v any
if err := unmarshal(&v); err != nil {
return err
}
switch val := v.(type) {
case string:
*s = strings.Split(val, ",")
return nil
case []any:
for _, item := range val {
if str, ok := item.(string); ok {
*s = append(*s, str)
} else {
return fmt.Errorf("element in sequence is not a string: %v", item)
}
}
return nil
}
return fmt.Errorf("cannot unmarshal %T into StringOrStringSlice", v)
}
func (r Config) SourceConfigType() string {
// Returns BigQuery source type
return SourceType
}
func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {
if r.WriteMode == "" {
r.WriteMode = WriteModeAllowed
if r.ReadOnly != nil && *r.ReadOnly {
r.WriteMode = WriteModeBlocked
}
}
if r.WriteMode != WriteModeAllowed && r.WriteMode != WriteModeBlocked && r.WriteMode != WriteModeProtected {
return nil, fmt.Errorf("invalid writeMode %q: must be one of %q, %q, or %q", r.WriteMode, WriteModeAllowed, WriteModeProtected, WriteModeBlocked)
}View on GitHub (pinned to 8cc6e09de2)
Solutions
- Check the YAML field: it must be a single string or a list of strings.
- Quote every element in the list so YAML does not parse it as a number or boolean (e.g. ["123", "true"]).
- If you need a single value, write it as a plain string instead of a nested list/map.
Example fix
// before (invalid: non-string element) allowedDatasets: - 12345 - mydataset // after allowedDatasets: - "12345" - mydataset
Defensive patterns
Strategy: validation
Validate before calling
func validateStringOrStringSlice(v interface{}) error {
normalize := func(s interface{}) error {
_, ok := s.(string)
if !ok { return fmt.Errorf("not a string: %v", s) }
return nil
}
switch t := v.(type) {
case string, nil:
return nil
case []interface{}:
for _, item := range t {
if err := normalize(item); err != nil { return err }
}
return nil
default:
return fmt.Errorf("cannot unmarshal %T into StringOrStringSlice", v)
}
} Type guard
func isStringOrStringSlice(v interface{}) bool {
switch t := v.(type) {
case string:
return true
case []interface{}:
for _, item := range t {
if _, ok := item.(string); !ok { return false }
}
return true
default:
return false
}
} Try / catch
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
if strings.Contains(err.Error(), "StringOrStringSlice") {
log.Fatalf("config field must be a string or list of strings: %v", err)
}
return err
} Prevention
- Quote ambiguous YAML scalars (numeric-looking IDs, booleans) in tools.yaml.
- Run the config through a YAML linter before deployment.
- Keep list elements on their own lines with proper '- ' syntax.
When it happens
Trigger: Parsing a BigQuery source YAML config where a field of type StringOrStringSlice (e.g. allowedDatasets) is given a YAML scalar of non-string type (integer, bool), a nested mapping, or a list whose elements are not all strings.
Common situations: Writing `allowedDatasets: 123` or `allowedDatasets: [mydataset, 42]` in tools.yaml; quoting mistakes that turn a list into a map; typos producing a nested structure where a string list was expected.
Related errors
- dialect invalid: must be one of "googlesql", or "postgresql"
- failed to unmarshal context from yaml: %w
- doc %d: unexpected non-string key in input: %v
- doc %d: invalid config format at key %q: %w
- doc %d: invalid config format at key %q: expected nested for
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/51e81686cce6cdc3.
Report an issue: GitHub.