{"record":{"id":"fc61a405c77dad7f","repo":"Tencent/WeKnora","slug":"api-key-is-required-for-tavily-provider-fc61a4","errorCode":null,"errorMessage":"API key is required for Tavily provider","messagePattern":"API key is required for Tavily provider","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/tavily.go","lineNumber":37,"sourceCode":"\t// Not configurable by tenants — prevents SSRF.\n\tdefaultTavilySearchURL = \"https://api.tavily.com/search\"\n)\n\nvar (\n\tdefaultTavilyTimeout = 15 * time.Second\n)\n\n// TavilyProvider implements web search using Tavily Search API\ntype TavilyProvider struct {\n\tclient  *http.Client\n\tbaseURL string\n\tapiKey  string\n}\n\n// NewTavilyProvider creates a new Tavily provider from parameters (no environment variables).\nfunc NewTavilyProvider(params types.WebSearchProviderParameters) (interfaces.WebSearchProvider, error) {\n\tif params.APIKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"API key is required for Tavily provider\")\n\t}\n\tclient, err := NewSearchHTTPClient(defaultTavilyTimeout, params.ProxyURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &TavilyProvider{\n\t\tclient:  client,\n\t\tbaseURL: defaultTavilySearchURL,\n\t\tapiKey:  params.APIKey,\n\t}, nil\n}\n\n// Name returns the provider name\nfunc (p *TavilyProvider) Name() string {\n\treturn \"tavily\"\n}\n\n// Search performs a web search using Tavily Search API","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/tavily.go#L19-L55","documentation":"NewTavilyProvider requires a Tavily API key in params.APIKey; Tavily's search API is authenticated and there is no anonymous mode. The constructor fails fast rather than letting every Search call later fail with an HTTP 401.","triggerScenarios":"Calling NewTavilyProvider(types.WebSearchProviderParameters{ProxyURL: ...}) without setting APIKey — e.g. tenant config missing the key, env var not loaded into the parameters struct, or a provider-type mismatch sending Tavily params without a key.","commonSituations":"TAVILY_API_KEY not set in the deployment environment and never copied into WebSearchProviderParameters; config file with an empty api_key field; rotating keys and temporarily blanking the value.","solutions":["Set the API key in the parameters: params.APIKey = os.Getenv(\"TAVILY_API_KEY\") or the tenant config value","Verify the deployment env/config actually carries the key (kubectl describe pod / docker inspect / .env)","Fix the config-loading path that builds WebSearchProviderParameters so the key field is populated","Validate key presence at startup and fail configuration load early with a clear message"],"exampleFix":"// before\nprovider, err := NewTavilyProvider(types.WebSearchProviderParameters{ProxyURL: proxy})\n// after\nprovider, err := NewTavilyProvider(types.WebSearchProviderParameters{\n    APIKey:   os.Getenv(\"TAVILY_API_KEY\"),\n    ProxyURL: proxy,\n})","handlingStrategy":"validation","validationCode":"if os.Getenv(\"TAVILY_API_KEY\") == \"\" {\n    return fmt.Errorf(\"TAVILY_API_KEY must be set before constructing the Tavily provider\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fail fast at startup when required credentials are absent","Keep API keys in a secrets manager and inject them into the environment","Validate WebSearchProviderParameters before constructing providers"],"tags":["api-key","authentication","config","tavily","missing-credential"],"backgroundTag":"missing-api-key","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}