{"record":{"id":"eaf8093a0516c789","repo":"crowdsecurity/crowdsec","slug":"failed-to-build-hub-index-request-w","errorCode":null,"errorMessage":"failed to build hub index request: %w","messagePattern":"failed to build hub index request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cwhub/download.go","lineNumber":59,"sourceCode":"\n\traw := fmt.Sprintf(d.URLTemplate, d.Branch, remotePath)\n\n\tparsed, err := url.Parse(raw)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse URL: %w\", err)\n\t}\n\n\treturn parsed, nil\n}\n\n// FetchIndex downloads the index from the hub and writes it to the filesystem.\n// It uses a temporary file to avoid partial downloads, and won't overwrite the original\n// if it has not changed.\n// Return true if the file has been updated, false if already up to date.\nfunc (d *Downloader) FetchIndex(ctx context.Context, destPath string, withContent bool, logger *logrus.Logger) (downloaded bool, err error) {\n\turl, err := d.urlTo(\".index.json\")\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to build hub index request: %w\", err)\n\t}\n\n\tif withContent {\n\t\tq := url.Query()\n\t\tq.Set(\"with_content\", \"true\")\n\t\turl.RawQuery = q.Encode()\n\t}\n\n\tdownloaded, err = downloader.\n\t\tNew().\n\t\tWithHTTPClient(HubClient).\n\t\tToFile(destPath).\n\t\tWithETagFn(downloader.SHA256).\n\t\tCompareContent().\n\t\tWithLogger(logger.WithField(\"url\", url)).\n\t\tBeforeRequest(func(_ *http.Request) {\n\t\t\tfmt.Fprintln(os.Stdout, \"Downloading \" + destPath)\n\t\t}).","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/cwhub/download.go#L41-L77","documentation":"FetchIndex wraps the error returned by Downloader.urlTo when it cannot construct the URL for the hub index file (.index.json). This means the Downloader's base URL was missing or malformed, so no HTTP request was even attempted. The wrap preserves the underlying cause.","triggerScenarios":"Calling Downloader.FetchIndex when the downloader has no valid base API URL configured (empty HubIndex URL, or urlTo fails to parse the resulting URL string).","commonSituations":"Hub URL misconfigured in config.yaml / dev.yaml (empty or typo'd api_url), environment where the hub URL was overridden to an invalid string, or a build/config migration that left the URL unset.","solutions":["Check the `api_url` (hub) setting in your crowdsec config file is set and is a valid absolute URL","Run `cscli hub update -o raw` or inspect `cscli config show` to see the hub URL in use","Fix the config value or restore the default hub URL, then retry `cscli hub update`"],"exampleFix":"// before (config.yaml)\napi:\n  hub:\n    api_url: \"\"\n// after\napi:\n  hub:\n    api_url: \"https://hub.crowdsec.net\"","handlingStrategy":"try-catch","validationCode":"if u, err := url.Parse(cfg.HubAPIURL); err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return fmt.Errorf(\"hub api_url %q is not a valid absolute URL\", cfg.HubAPIURL)\n}","typeGuard":null,"tryCatchPattern":"downloaded, err := d.FetchIndex(ctx, dest, withContent, logger)\nvar urlErr *url.Error\nif errors.As(err, &urlErr) {\n    logger.Errorf(\"hub URL invalid: %v — check api_url in config\", urlErr)\n    return\n}","preventionTips":["Always set a valid absolute hub api_url in config","Validate config URLs at startup before any hub operation","Smoke-test with `cscli hub update` after config changes"],"tags":["network","url","config","hub"],"backgroundTag":"invalid-url-format","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}