projectdiscovery/nuclei · error
could not upload results got status code %v on %v
Error message
could not upload results got status code %v on %v
What it means
The periodic results upload POST returned a non-200 status (internal/pdcp/writer.go:228); the error includes both the status code and the exact request URL, which distinguishes auth problems (401/403), wrong endpoints (404), rate limiting (429) and server faults (5xx). Transport-level failures surface separately as errkit-wrapped 'could not upload results', so this error specifically means the server answered with an unexpected status. The response body is read first, and a successful ID is recorded only on 200.
Source
Thrown at internal/pdcp/writer.go:228
func (u *UploadWriter) upload(data []byte) error {
req, err := u.getRequest(data)
if err != nil {
return errkit.Wrap(err, "could not create upload request")
}
resp, err := u.client.Do(req)
if err != nil {
return errkit.Wrap(err, "could not upload results")
}
defer func() {
_ = resp.Body.Close()
}()
bin, err := io.ReadAll(resp.Body)
if err != nil {
return errkit.Wrap(err, "could not get id from response")
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("could not upload results got status code %v on %v", resp.StatusCode, resp.Request.URL.String())
}
var uploadResp uploadResponse
if err := json.Unmarshal(bin, &uploadResp); err != nil {
return errkit.Wrap(err, fmt.Sprintf("could not unmarshal response got %v", string(bin)))
}
if uploadResp.ID != "" && u.scanID == "" {
u.scanID = uploadResp.ID
}
return nil
}
// getRequest returns a new request for upload
// if scanID is not provided create new scan by uploading the data
// if scanID is provided append the data to existing scan
func (u *UploadWriter) getRequest(bin []byte) (*retryablehttp.Request, error) {
var method, url string
if u.scanID == "" {View on GitHub (pinned to 265b3a3dec)
Solutions
- On 401/403 re-authenticate (nuclei auth) and verify team membership/permissions
- Confirm the configured API server URL points at the intended PDCP endpoint
- Treat 429/5xx as transient — uploads are periodic and usually self-heal on later ticks
- Check the ProjectDiscovery cloud status for incidents
Defensive patterns
Strategy: retry
Try / catch
err := uploadTick(ctx)
if err != nil {
msg := err.Error()
if strings.Contains(msg, "status code 401") || strings.Contains(msg, "status code 403") {
return fmt.Errorf("pdcp token rejected: re-authenticate") // fail fast
}
if strings.Contains(msg, "status code 429") || strings.Contains(msg, "status code 5") {
backoff.RetryNotify(uploadTick, backoff.NewExponentialBackOff(), notify) // transient
}
return err
} Prevention
- Refresh credentials before very long scans
- Pin the correct API server URL in configuration
- Treat 5xx/429 as transient; the writer uploads periodically and recovers on later ticks
- Alert on repeated upload failures rather than failing the scan
When it happens
Trigger: Expired or invalid PDCP token (401); token lacking access to the team/scan (403); misconfigured custom API base URL (404); upstream incidents or rate limits (429/5xx) during long scans.
Common situations: Long-running scans whose token expires mid-run; rotated or revoked API keys; wrong -server URL; upstream service degradation.
Related errors
- no credentials provided
- authentication failed
- Invalid protocol type: {valueToMap}
- invalid workflow with no templates or tags
- prompt not found (read cap reached)
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/6e61c609454f3cba.
Report an issue: GitHub.