projectdiscovery/subfinder · error
%s
Error message
%s
What it means
PugRecon received a non-200 HTTP status from its API. The source builds an error message with the status code and, if the body decodes as the API response with a Message field, appends the API's message (e.g. quota or auth errors). This is the source's generic API-error channel.
Solutions
- Read the appended API message after the status code for the exact cause
- Renew or correct the PugRecon API token in subfinder config (provider-settings)
- Check your PugRecon plan quota; upgrade or wait for reset if quota exceeded
- Retry later if the status is 5xx (server-side outage)
Defensive patterns
Strategy: validation
Validate before calling
// pre-validate config
if token == "" { return errors.New("pugrecon API key missing in provider config") } Try / catch
// inspect the appended API message to branch
if strings.Contains(errMsg, "quota") {
// wait for reset / upgrade plan
} else if resp.StatusCode == 401 {
// refresh token
} Prevention
- Keep the PugRecon API token current in provider settings
- Monitor plan quota before bulk enumeration
- Handle 5xx with delayed retries
When it happens
Trigger: The POST to the PugRecon API returns a status other than 200 (401 invalid/expired session token, 402/429 quota exceeded, 5xx server error); the response Message is appended when present.
Common situations: Expired or missing Pugrecon session/auth token in config; exhausted API quota on a free plan; PugRecon outage causing 5xx.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- request failed with status
- failed to close response body
- %s
- unexpected status code
- unexpected status code
AI-assisted analysis of projectdiscovery/subfinder@7a0b91f0fa (2026-09-06).
Data as JSON: /api/errors/2143f553784ae26a.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/subscraping/sources/pugrecon/pugrecon.go:98
s.errors++
session.DiscardHTTPResponse(resp)
return
}
defer func() {
if err := resp.Body.Close(); err != nil {
results <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: fmt.Errorf("failed to close response body: %w", err)}
s.errors++
}
}()
if resp.StatusCode != http.StatusOK {
errorMsg := fmt.Sprintf("received status code %d", resp.StatusCode)
// Attempt to read error message from body if possible
var apiResp pugreconAPIResponse
if json.NewDecoder(resp.Body).Decode(&apiResp) == nil && apiResp.Message != "" {
errorMsg = fmt.Sprintf("%s: %s", errorMsg, apiResp.Message)
}
results <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: fmt.Errorf("%s", errorMsg)}
s.errors++
return
}
var response pugreconAPIResponse
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil {
results <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: err}
s.errors++
return
}
for _, subdomain := range response.Results {
select {
case <-ctx.Done():
return
case results <- subscraping.Result{Source: s.Name(), Type: subscraping.Subdomain, Value: subdomain.Name}:
s.results++View on GitHub (pinned to 7a0b91f0fa)