{"record":{"id":"21b965f96484b8fd","repo":"gocolly/colly","slug":"erremptyproxyurl","errorCode":"ErrEmptyProxyURL","errorMessage":"Proxy URL list is empty","messagePattern":"Proxy URL list is empty","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"colly.go","lineNumber":242,"sourceCode":"\t// ErrMissingURL is the error type for missing URL errors\n\tErrMissingURL = errors.New(\"Missing URL\")\n\t// ErrMaxDepth is the error type for exceeding max depth\n\tErrMaxDepth = errors.New(\"Max depth limit reached\")\n\t// ErrForbiddenURL is the error thrown if visiting\n\t// a URL which is not allowed by URLFilters\n\tErrForbiddenURL = errors.New(\"ForbiddenURL\")\n\n\t// ErrNoURLFiltersMatch is the error thrown if visiting\n\t// a URL which is not allowed by URLFilters\n\tErrNoURLFiltersMatch = errors.New(\"No URLFilters match\")\n\t// ErrRobotsTxtBlocked is the error type for robots.txt errors\n\tErrRobotsTxtBlocked = errors.New(\"URL blocked by robots.txt\")\n\t// ErrNoCookieJar is the error type for missing cookie jar\n\tErrNoCookieJar = errors.New(\"Cookie jar is not available\")\n\t// ErrNoPattern is the error type for LimitRules without patterns\n\tErrNoPattern = errors.New(\"No pattern defined in LimitRule\")\n\t// ErrEmptyProxyURL is the error type for empty Proxy URL list\n\tErrEmptyProxyURL = errors.New(\"Proxy URL list is empty\")\n\t// ErrAbortedAfterHeaders is the error returned when OnResponseHeaders aborts the transfer.\n\tErrAbortedAfterHeaders = errors.New(\"Aborted after receiving response headers\")\n\t// ErrAbortedBeforeRequest is the error returned when OnResponseHeaders aborts the transfer.\n\tErrAbortedBeforeRequest = errors.New(\"Aborted before Do Request\")\n\t// ErrQueueFull is the error returned when the queue is full\n\tErrQueueFull = errors.New(\"Queue MaxSize reached\")\n\t// ErrMaxRequests is the error returned when exceeding max requests\n\tErrMaxRequests = errors.New(\"Max Requests limit reached\")\n\t// ErrRetryBodyUnseekable is the error when retry with not seekable body\n\tErrRetryBodyUnseekable = errors.New(\"Retry Body Unseekable\")\n)\n\nvar envMap = map[string]func(*Collector, string){\n\t\"ALLOWED_DOMAINS\": func(c *Collector, val string) {\n\t\tc.AllowedDomains = strings.Split(val, \",\")\n\t},\n\t\"CACHE_DIR\": func(c *Collector, val string) {\n\t\tc.CacheDir = val","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/gocolly/colly/blob/17d1d6ca92bd32a5651f34256bf7a2855c967f65/colly.go#L224-L260","documentation":"ErrEmptyProxyURL is returned by NewRoundRobinProxySwitcher when the supplied proxy URL list is empty. The proxy switcher needs at least one proxy to rotate through; with an empty slice there is nothing to switch to, so construction fails immediately.","triggerScenarios":"Calling colly.NewRoundRobinProxySwitcher([]string{}) or with a slice that is nil; building the proxy list from config/env/file parsing that yielded no entries (empty env var, missing file, all lines filtered out); passing a slice after filtering removed all invalid entries.","commonSituations":"Reading PROXY_LIST env var that is unset, producing an empty split; a proxies.txt file that is empty or has only comments; dynamic proxy pools that were pruned to zero healthy proxies before the switcher was created.","solutions":["Ensure the proxy slice passed to NewRoundRobinProxySwitcher has at least one URL","Validate the proxy list at startup and fail fast with a clear message before constructing the switcher","If proxies are optional, only build/attach the switcher when len(proxies) > 0","Check the source of the list (env var, file, API) actually returned entries"],"exampleFix":"// before\nproxies := strings.Split(os.Getenv(\"PROXY_LIST\"), \",\") // may be [\"\"] or empty\nswitcher, _ := colly.NewRoundRobinProxySwitcher(proxies) // ErrEmptyProxyURL\n// after\nproxies := strings.Split(os.Getenv(\"PROXY_LIST\"), \",\")\nif len(proxies) > 0 && proxies[0] != \"\" {\n    switcher, err := colly.NewRoundRobinProxySwitcher(proxies)\n    c.SetProxyFunc(switcher)\n}","handlingStrategy":"validation","validationCode":"proxies := strings.Split(os.Getenv(\"PROXY_LIST\"), \",\")\nvar valid []string\nfor _, p := range proxies {\n    if u, err := url.Parse(strings.TrimSpace(p)); err == nil && u.Scheme != \"\" {\n        valid = append(valid, p)\n    }\n}\nif len(valid) == 0 {\n    return fmt.Errorf(\"no proxy URLs configured\")\n}\nswitcher, err := colly.NewRoundRobinProxySwitcher(valid)","typeGuard":"func hasProxies(list []string) bool {\n    return len(list) > 0 && list[0] != \"\"\n}","tryCatchPattern":"switcher, err := colly.NewRoundRobinProxySwitcher(proxies)\nif err != nil {\n    if errors.Is(err, colly.ErrEmptyProxyURL) {\n        log.Println(\"proxy list empty, running without proxy\")\n        return nil\n    }\n    return err\n}","preventionTips":["Check that the env/file source of the proxy list actually yielded entries","Trim and validate each proxy URL before building the switcher","Only construct the switcher when len(proxies) > 0"],"tags":["colly","scraping","proxy","configuration","go"],"backgroundTag":"empty-proxy-list","analyzedSha":"17d1d6ca92bd32a5651f34256bf7a2855c967f65","analyzedAt":"2026-08-30T21:32:31.579Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}