{"record":{"id":"e6715b3fc949d917","repo":"wtfutil/wtf","slug":"s-e6715b","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/subreddit/api.go","lineNumber":40,"sourceCode":"\t}\n\n\trequest.Header.Set(\"User-Agent\", \"wtfutil (https://github.com/wtfutil/wtf)\")\n\n\t// See https://www.reddit.com/r/redditdev/comments/t8e8hc/comment/i18yga2/?utm_source=share&utm_medium=web2x&context=3\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tTLSNextProto: map[string]func(authority string, c *tls.Conn) http.RoundTripper{},\n\t\t},\n\t}\n\tresp, err := client.Do(request)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode > 299 {\n\t\treturn nil, fmt.Errorf(\"%s\", resp.Status)\n\t}\n\tvar m RedditDocument\n\terr = utils.ParseJSON(&m, resp.Body)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(m.Data.Children) == 0 {\n\t\treturn nil, fmt.Errorf(\"no links\")\n\t}\n\n\tvar links []Link\n\tfor _, l := range m.Data.Children {\n\t\tlinks = append(links, l.Data)\n\t}\n\treturn links, nil\n}","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/wtfutil/wtf/blob/bb838c1ccb0f0f3223690df44afdec663d622881/modules/subreddit/api.go#L22-L58","documentation":"GetLinks in the subreddit module performs a Reddit HTTP request and rejects any response with status code above 299, returning the raw resp.Status string (e.g. \"429 Too Many Requests\") as the error. Since it returns the status text, the cause is directly readable.","triggerScenarios":"Any Reddit API response with status 300+: 403/429 from rate limiting or blocked user-agent, 404 for a nonexistent subreddit, 5xx Reddit outages.","commonSituations":"Reddit rate-limiting aggressive polling; subreddit renamed/private/banned; missing or generic User-Agent being throttled; Reddit returning 403 to unauthenticated API calls on restricted subreddits.","solutions":["Check the returned status string: 429 means reduce refresh interval","Verify the subreddit name in config exists and is public","Set a descriptive custom User-Agent to avoid Reddit's default-UA throttling","Retry later on 5xx statuses"],"exampleFix":"// before\n\"subreddit\": \"golangxxxx\" // 404\n// after\n\"subreddit\": \"golang\"","handlingStrategy":"retry","validationCode":"if subreddit == \"\" || strings.ContainsAny(subreddit, \"/?&\") { return errors.New(\"invalid subreddit name\") }","typeGuard":"func isRateLimited(status string) bool { return strings.HasPrefix(status, \"429\") }","tryCatchPattern":"links, err := GetLinks(subreddit)\nif err != nil {\n    var status string\n    if strings.HasPrefix(err.Error(), \"429\") { waitAndRetry() } else { log.Printf(\"reddit: %v\", err) }\n    _ = status\n}","preventionTips":["Set a descriptive custom User-Agent for Reddit requests","Keep the subreddit refresh interval moderate (Reddit rate-limits aggressively)","Validate subreddit names exist and are public before adding them","Expect and handle 403 for quarantined/private subreddits"],"tags":["http","reddit","network","go"],"backgroundTag":"http-non-200-response","analyzedSha":"bb838c1ccb0f0f3223690df44afdec663d622881","analyzedAt":"2026-09-03T17:02:45.030Z","contentChangedAt":"2026-09-03T17:02:45.030Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}