{"record":{"id":"f36235e96cd7aabc","repo":"Tencent/WeKnora","slug":"query-is-empty-f36235","errorCode":null,"errorMessage":"query is empty","messagePattern":"query is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/tavily.go","lineNumber":63,"sourceCode":"\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\nfunc (p *TavilyProvider) Search(\n\tctx context.Context,\n\tquery string,\n\tmaxResults int,\n\tincludeDate bool,\n) ([]*types.WebSearchResult, error) {\n\tif len(query) == 0 {\n\t\treturn nil, fmt.Errorf(\"query is empty\")\n\t}\n\tlogger.Infof(ctx, \"[WebSearch][Tavily] query=%q maxResults=%d url=%s\", query, maxResults, p.baseURL)\n\n\treqBody := tavilySearchRequest{\n\t\tAPIKey:     p.apiKey,\n\t\tQuery:      query,\n\t\tMaxResults: maxResults,\n\t}\n\n\tbodyBytes, err := json.Marshal(reqBody)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal request: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, \"POST\", p.baseURL, bytes.NewReader(bodyBytes))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create request: %w\", err)\n\t}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/tavily.go#L45-L81","documentation":"Search() rejects an empty query (len(query) == 0) before contacting Tavily. Note it does not trim whitespace, unlike the SearXNG provider, so a space-only string passes here and is sent to the API. Tavily cannot execute a meaningful search for an empty query, so the provider fails fast client-side.","triggerScenarios":"Calling Search(ctx, \"\", n, false) on a TavilyProvider; empty string produced by upstream keyword extraction or an unfilled template variable.","commonSituations":"Empty user input flowing through a RAG pipeline; optional search step invoked unconditionally with a possibly-blank query string.","solutions":["Trim and check the query before calling Search; skip the search step for blank input","Use strings.TrimSpace to also catch whitespace-only queries (this provider only checks length)","Fix the upstream query-producing code so it never yields empty strings","Return a benign empty result set rather than surfacing an error for blank queries"],"exampleFix":"// before\nresults, err := provider.Search(ctx, query, 5, false)\n// after\nquery = strings.TrimSpace(query)\nif query == \"\" {\n    return nil, nil // skip search for blank query\n}\nresults, err := provider.Search(ctx, query, 5, false)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(query) == \"\" {\n    return nil, nil // skip search\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["TrimSpace queries (this provider only checks len == 0, so whitespace passes)","Skip search calls when upstream produced no keywords","Centralize query sanitization before any provider's Search is invoked"],"tags":["validation","input-validation","tavily","empty-input"],"backgroundTag":"empty-query-parameter","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}