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

  1. Read the appended API message after the status code for the exact cause
  2. Renew or correct the PugRecon API token in subfinder config (provider-settings)
  3. Check your PugRecon plan quota; upgrade or wait for reset if quota exceeded
  4. 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

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


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)