{"record":{"id":"9d3560ae5b5ac896","repo":"googleapis/mcp-toolbox","slug":"filter-expression-must-be-a-string-got-t","errorCode":null,"errorMessage":"'filter_expression' must be a string, got %T","messagePattern":"'filter_expression' must be a string, got %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/looker/lookercommon/lookercommon.go","lineNumber":355,"sourceCode":"\n\tvar tz string\n\tif paramsMap[\"tz\"] != nil {\n\t\ttz = paramsMap[\"tz\"].(string)\n\t} else {\n\t\ttzname, err := tzlocal.RuntimeTZ()\n\t\tif err != nil {\n\t\t\tlogger.ErrorContext(ctx, fmt.Sprintf(\"Error getting local timezone: %s\", err))\n\t\t\ttzname = \"Etc/UTC\"\n\t\t}\n\t\ttz = tzname\n\t}\n\n\tvar filterExpressionPtr *string\n\tif val, ok := paramsMap[\"filter_expression\"]; ok && val != nil {\n\t\tif strVal, ok := val.(string); ok {\n\t\t\tfilterExpressionPtr = &strVal\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"'filter_expression' must be a string, got %T\", val)\n\t\t}\n\t}\n\n\tvar dynamicFieldsPtr *string\n\tif val, ok := paramsMap[\"dynamic_fields\"]; ok && val != nil {\n\t\tif sliceVal, ok := val.([]any); ok && len(sliceVal) > 0 {\n\t\t\tjsonBytes, err := json.Marshal(sliceVal)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error marshaling dynamic_fields: %w\", err)\n\t\t\t}\n\t\t\tjsonStr := string(jsonBytes)\n\t\t\tdynamicFieldsPtr = &jsonStr\n\t\t}\n\t}\n\n\twq := v4.WriteQuery{\n\t\tModel:            paramsMap[\"model\"].(string),\n\t\tView:             paramsMap[\"explore\"].(string),","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/looker/lookercommon/lookercommon.go#L337-L373","documentation":"ProcessQueryArgs validates that the optional 'filter_expression' parameter is a string (Looker expects the Looker filter expression language as text). If the value is present and non-nil but is any other Go type, the function returns this typed error including the offending %T type.","triggerScenarios":"Calling the tool with filter_expression set to a number, bool, array, or object, e.g. filter_expression: 123 or filter_expression: {\"field\":\"x\"}.","commonSituations":"Clients constructing filter expressions as structured JSON objects (as in other BI APIs) instead of Looker expression strings; agents emitting unquoted values; template rendering producing non-string types.","solutions":["Pass filter_expression as a string, e.g. \"users.created_date >= '2024-01-01'\"","Serialize structured filters into Looker expression syntax manually before sending","Remove the parameter entirely if no filter expression is needed (it is optional)","Check the %T in the message to see which type was actually sent"],"exampleFix":"// before\n\"filter_expression\": {\"field\": \"users.age\", \"gt\": 30}\n// after\n\"filter_expression\": \"users.age > 30\"","handlingStrategy":"type-guard","validationCode":"if v, ok := params[\"filter_expression\"]; ok && v != nil {\n\tif _, ok := v.(string); !ok {\n\t\treturn fmt.Errorf(\"filter_expression must be a string\")\n\t}\n}","typeGuard":"func isString(v any) bool { _, ok := v.(string); return ok }","tryCatchPattern":null,"preventionTips":["Express Looker filters in Looker filter-expression string syntax","Quote filter values in generated JSON","Never pass structured objects where the schema says string"],"tags":["looker","type-error","parameters"],"backgroundTag":"parameter-type-mismatch","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}