{"record":{"id":"8778e89da6aefd92","repo":"Tencent/WeKnora","slug":"invalid-searxng-base-url-must-be-an-absolute-http","errorCode":null,"errorMessage":"invalid SearXNG base_url: must be an absolute http(s) URL","messagePattern":"invalid SearXNG base_url: must be an absolute http\\(s\\) URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/searxng.go","lineNumber":47,"sourceCode":"// to the SSRF_WHITELIST environment variable.\ntype SearxngProvider struct {\n\tclient           *http.Client\n\tbaseURL          string\n\tlastUnresponsive [][]string\n}\n\n// ValidateSearxngBaseURL validates a SearXNG instance URL: must be a non-empty,\n// absolute http(s) URL, and must pass the SSRF whitelist check. Shared between\n// the service-layer parameter validation and the provider constructor so that\n// \"save\" and \"use\" never disagree.\nfunc ValidateSearxngBaseURL(rawURL string) error {\n\tbase := strings.TrimSpace(rawURL)\n\tif base == \"\" {\n\t\treturn fmt.Errorf(\"base_url is required for SearXNG provider\")\n\t}\n\tparsed, err := url.Parse(base)\n\tif err != nil || parsed.Scheme == \"\" || parsed.Host == \"\" {\n\t\treturn fmt.Errorf(\"invalid SearXNG base_url: must be an absolute http(s) URL\")\n\t}\n\tif parsed.Scheme != \"http\" && parsed.Scheme != \"https\" {\n\t\treturn fmt.Errorf(\"invalid SearXNG base_url scheme: %s\", parsed.Scheme)\n\t}\n\tif parsed.RawQuery != \"\" || parsed.Fragment != \"\" {\n\t\treturn fmt.Errorf(\"invalid SearXNG base_url: must not contain query or fragment\")\n\t}\n\tif err := utils.ValidateURLForSSRF(base); err != nil {\n\t\treturn fmt.Errorf(\"invalid SearXNG base_url: %w\", err)\n\t}\n\treturn nil\n}\n\n// NewSearxngProvider builds a SearXNG provider from tenant parameters.\nfunc NewSearxngProvider(params types.WebSearchProviderParameters) (interfaces.WebSearchProvider, error) {\n\tbase := strings.TrimSpace(params.BaseURL)\n\tif err := ValidateSearxngBaseURL(base); err != nil {\n\t\treturn nil, err","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/searxng.go#L29-L65","documentation":"The provided SearXNG base_url is not an absolute http(s) URL: url.Parse failed, or the parsed URL has no scheme or no host. The function demands a fully qualified absolute URL before applying further scheme and SSRF checks.","triggerScenarios":"NewSearxngProvider or the save-validation path receives base_url values like \"localhost:8080/searxng\", \"searx.example.com\", or a malformed URL that url.Parse cannot handle.","commonSituations":"Users omitting the https:// prefix, relative paths pasted from docs, DNS-only names without scheme, URLs copied with missing characters.","solutions":["Prepend the scheme: \"searx.example.com\" -> \"https://searx.example.com\"","Ensure both scheme and host exist (e.g. not just \"https://\")","Validate with url.Parse in a quick snippet before saving config","Use the full instance URL including base path if any, e.g. https://host/searxng"],"exampleFix":"// before\nbaseURL := \"searx.example.com\"\n// after\nbaseURL := \"https://searx.example.com\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(baseURL)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return fmt.Errorf(\"base_url must be absolute, e.g. https://searx.example.com (got %q)\", baseURL)\n}","typeGuard":null,"tryCatchPattern":"if err := web_search.ValidateSearxngBaseURL(cfg.BaseURL); err != nil {\n    if strings.Contains(err.Error(), \"absolute http(s) URL\") {\n        return fmt.Errorf(\"fix base_url: prepend https:// to the host\")\n    }\n    return err\n}","preventionTips":["Always enter the full URL including scheme in config/UI","Auto-prepend https:// when the user supplies a bare hostname (with confirmation)","Validate URLs at save time, not at request time","Reject relative paths early in config parsing"],"tags":["url","validation","searxng","configuration"],"backgroundTag":"invalid-url-format","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}