{"record":{"id":"a79a1115e885cc33","repo":"crowdsecurity/crowdsec","slug":"failed-to-parse-url-w","errorCode":null,"errorMessage":"failed to parse URL: %w","messagePattern":"failed to parse URL: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cwhub/download.go","lineNumber":46,"sourceCode":"}\n\n// ContentProvider retrieves and writes the YAML files with the item content.\ntype ContentProvider interface {\n\tFetchContent(ctx context.Context, remotePath, destPath, wantHash string, logger *logrus.Logger) (bool, string, error)\n}\n\n// urlTo builds the URL to download a file from the remote hub.\nfunc (d *Downloader) urlTo(remotePath string) (*url.URL, error) {\n\t// the template must contain two string placeholders\n\tif fmt.Sprintf(d.URLTemplate, \"%s\", \"%s\") != d.URLTemplate {\n\t\treturn nil, fmt.Errorf(\"invalid URL template '%s'\", d.URLTemplate)\n\t}\n\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\")","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/cwhub/download.go#L28-L64","documentation":"After substituting the branch and remote path into the downloader's URL template, urlTo parses the result with url.Parse. If the resulting string is not a parseable URL (e.g. invalid characters, bad scheme), it returns 'failed to parse URL' wrapping the net/url error, failing FetchIndex/FetchContent.","triggerScenarios":"URLTemplate (after branch+remotePath substitution) yields a string url.Parse rejects: control characters or spaces in the hub URL or remote path, an empty/malformed scheme, or a path containing invalid percent sequences.","commonSituations":"Whitespace or quotes accidentally included in the hub_url config value; a remote file path with characters that break URL syntax; a misconfigured custom mirror URL with typos.","solutions":["Inspect the wrapped net/url error for the offending character/position.","Remove stray spaces/quotes/control characters from the hub URL in config.yaml.","Validate the final URL by pasting it into a browser or `curl -I`.","If the offending character comes from the remote path (index file name), update/re-fetch the hub index; this may be an upstream index issue."],"exampleFix":"// before (config.yaml)\nhub_url: \" https://hub.example.com/%s/%s\"  # leading space\n// after\nhub_url: \"https://hub.example.com/%s/%s\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(fmt.Sprintf(template, branch, remotePath))\nif err != nil {\n    return fmt.Errorf(\"resulting hub URL is invalid: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"u, err := d.urlTo(remotePath)\nif err != nil {\n    return fmt.Errorf(\"cannot build hub URL: %w\", err)\n}","preventionTips":["Strip whitespace/quotes from hub_url values in config","Verify the substituted URL with curl before automating downloads","Keep remote file paths URL-safe; re-fetch the hub index if it references odd paths"],"tags":["hub","url","network"],"backgroundTag":"invalid-url","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"}