{"record":{"id":"6290c032a592bc08","repo":"googleapis/mcp-toolbox","slug":"unable-to-parse-timeout-string-as-time-duration-6290c0","errorCode":null,"errorMessage":"unable to parse Timeout string as time.Duration: %s","messagePattern":"unable to parse Timeout string as time\\.Duration: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/looker/looker.go","lineNumber":104,"sourceCode":"func (r Config) SourceConfigType() string {\n\treturn SourceType\n}\n\n// Initialize initializes a Looker Source instance.\nfunc (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {\n\tlogger, err := util.LoggerFromContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to get logger from ctx: %s\", err)\n\t}\n\n\tuserAgent, err := util.UserAgentFromContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tduration, err := time.ParseDuration(r.Timeout)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to parse Timeout string as time.Duration: %s\", err)\n\t}\n\n\tif !r.SslVerification {\n\t\tlogger.WarnContext(ctx, \"Insecure HTTP is enabled for Looker source %s. TLS certificate verification is skipped.\\n\", r.Name)\n\t}\n\tcfg := rtl.ApiSettings{\n\t\tAgentTag:     userAgent,\n\t\tBaseUrl:      r.BaseURL,\n\t\tApiVersion:   \"4.0\",\n\t\tVerifySsl:    r.SslVerification,\n\t\tTimeout:      int32(duration.Seconds()),\n\t\tClientId:     r.ClientId,\n\t\tClientSecret: r.ClientSecret,\n\t}\n\n\tvar tokenSource oauth2.TokenSource\n\ttokenSource, _ = initGoogleCloudConnection(ctx)\n","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/looker/looker.go#L86-L122","documentation":"The Looker source stores its client timeout as a string; Initialize parses it with time.ParseDuration. If the string is not a valid Go duration (e.g. \"30\" without a unit), initialization fails with this error. The parse error text is appended for diagnosis.","triggerScenarios":"Config with timeout: \"30\" (missing unit), \"thirty\", or an empty-but-nonzero string; anything time.ParseDuration rejects. Valid examples: \"30s\", \"1m30s\".","commonSituations":"Copy-pasting a timeout in seconds/milliseconds as a bare integer from other tooling; editing YAML and dropping the 's' suffix; assuming the field takes milliseconds.","solutions":["Set timeout to a valid Go duration string with a unit, e.g. \"30s\" or \"2m\".","If the field was intended to be empty/default, remove it so the default is used.","Validate the YAML (go duration syntax: number + unit suffix like ns/us/ms/s/m/h)."],"exampleFix":"# before\nsources:\n  looker:\n    kind: looker\n    timeout: \"30\"\n# after\nsources:\n  looker:\n    kind: looker\n    timeout: \"30s\"","handlingStrategy":"validation","validationCode":"// Go: validate the timeout config value before building the source config\nd, err := time.ParseDuration(cfg.Timeout)\nif err != nil {\n    return fmt.Errorf(\"looker timeout %q is not a valid Go duration (e.g. 30s, 2m): %w\", cfg.Timeout, err)\n}","typeGuard":null,"tryCatchPattern":"src, err := cfg.Initialize(ctx, tracer)\nif err != nil {\n    if strings.Contains(err.Error(), \"unable to parse Timeout string\") {\n        fmt.Printf(\"timeout %q must be a Go duration string like 30s — fix YAML\\n\", cfg.Timeout)\n    }\n    return err\n}","preventionTips":["Always include a unit suffix in timeout values: 30s, 5m — never a bare integer.","Lint toolbox YAML for Go duration fields in CI.","Remember the field is a string; millisecond integers from other tools must be converted."],"tags":["looker","config","duration","validation"],"backgroundTag":"invalid-duration-format","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}