{"record":{"id":"89a326dacffe43ca","repo":"janhq/jan","slug":"websearcherror-message","errorCode":null,"errorMessage":"WebSearchError: {message}","messagePattern":"WebSearchError: (.+?)","errorType":"exception","errorClass":"WebSearchError","httpStatus":null,"severity":"error","filePath":"src-tauri/plugins/tauri-plugin-websearch/src/commands.rs","lineNumber":5,"sourceCode":"use crate::provider::{clamp_count, create_provider, FetchedPage, SearchResult};\nuse serde::Serialize;\n\n#[derive(Debug, Clone, Serialize, thiserror::Error)]\n#[error(\"WebSearchError: {message}\")]\npub struct WebSearchError {\n    pub message: String,\n}\n\nimpl WebSearchError {\n    fn new(message: impl Into<String>) -> Self {\n        Self {\n            message: message.into(),\n        }\n    }\n}\n\nimpl From<String> for WebSearchError {\n    fn from(message: String) -> Self {\n        Self::new(message)\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/src-tauri/plugins/tauri-plugin-websearch/src/commands.rs#L1-L23","documentation":"WebSearchError is the unified error type returned by the web_search and web_fetch Tauri commands in the websearch plugin. It wraps a single message string and is constructed via WebSearchError::new() or the From<String> impl. Because it derives Serialize, it is directly serializable across the Tauri IPC boundary to the frontend.","triggerScenarios":"Calling web_search with an empty or whitespace-only query string. Calling web_fetch with a non-http(s) URL or empty URL. create_provider() failing because the provider name is unrecognized or the required API key is missing. The upstream search/fetch backend returning an HTTP error or timing out.","commonSituations":"Exa API key not set or expired, causing provider authentication failure. Network proxy or firewall blocking the Exa endpoint. User mistyped the provider name (e.g. 'exa' vs 'Exa'). URL with a trailing scheme typo like 'htps://'. Rate-limiting from the search provider.","solutions":["Verify the query/url argument is non-empty and well-formed before invoking the command.","Ensure a valid API key is configured for keyed backends (Exa) in settings.","Check network connectivity and that no proxy/firewall blocks the provider endpoint.","Use the default provider by passing None for provider to fall back to the configured backend."],"exampleFix":"// before\nconst results = await invoke('web_search', { query: '' });\n\n// after\nif (!query.trim()) {\n  toast.error('Search query is empty');\n  return;\n}\nconst results = await invoke('web_search', { query, provider: 'exa', api_key });","handlingStrategy":"validation","validationCode":"// Validate before calling web_search / web_fetch\nfunction validateSearchParams(query: string, provider?: string, apiKey?: string): string | null {\n  if (!query.trim()) return \"query must not be empty\";\n  if (provider && !['exa', 'tavily', 'serper'].includes(provider)) return `unknown provider: ${provider}`;\n  if (provider === 'exa' && !apiKey) return \"Exa requires an API key\";\n  return null;\n}\n\nfunction validateFetchUrl(url: string): string | null {\n  if (!url.trim()) return \"url must not be empty\";\n  if (!/^https?:\\/\\//.test(url)) return \"url must be http(s)\";\n  return null;\n}","typeGuard":"function isNonEmptyString(v: unknown): v is string {\n  return typeof v === 'string' && v.trim().length > 0;\n}\n\nfunction isValidHttpUrl(url: string): boolean {\n  try { const u = new URL(url); return u.protocol === 'http:' || u.protocol === 'https:'; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  const results = await invoke('web_search', { query, provider, api_key });\n} catch (e) {\n  const msg = e?.message ?? String(e);\n  if (msg.includes('must not be empty')) {\n    toast.error('Please enter a search query');\n  } else if (msg.includes('API key')) {\n    toast.error('Configure your API key in settings');\n  } else {\n    toast.error('Search failed', { description: msg });\n  }\n}","preventionTips":["Trim and validate the query before invoking the command.","Ensure API keys are configured in settings before calling keyed providers.","Catch WebSearchError at the call site and map it to user-friendly messages.","Test with the default provider first to isolate provider-specific issues."],"tags":["web-search","validation","api-key","network","tauri-command"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}