owasp-amass/amass · error
%s/stats: status=%s error=%s
Error message
%s/stats: status=%s error=%s
What it means
Returned by Client.SessionStats when GET /api/v1/sessions/{token}/stats returns a non-200 status and the response body is a decodable JSON error, so the message includes the server's error text after 'error=': '<token>/stats: status=<status> error=<msg>'. It reports exactly why the server refused to return statistics for that session.
Source
Thrown at engine/api/client/v1/client.go:180
return fmt.Errorf("terminateSession: status=%s error=%s", resp.Status, msg)
}
return nil
}
// Retrieves statistics for the session associated with the provided token.
func (c *Client) SessionStats(ctx context.Context, token uuid.UUID) (*et.SessionStats, error) {
resp, err := amasshttp.RequestWebPage(ctx, c.httpClient,
&amasshttp.Request{URL: c.base + "/sessions/" + token.String() + "/stats"})
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
msg, err := readJSONError(resp.Body)
if err != nil {
return nil, fmt.Errorf("%s/stats: status=%s", token.String(), resp.Status)
}
return nil, fmt.Errorf("%s/stats: status=%s error=%s", token.String(), resp.Status, msg)
}
var st et.SessionStats
if err := json.Unmarshal([]byte(resp.Body), &st); err != nil {
return nil, err
}
return &st, nil
}
// Retrieves scope for the session associated with the provided token.
func (c *Client) SessionScope(ctx context.Context, token uuid.UUID, atype oam.AssetType) ([]oam.Asset, error) {
sessionID := token.String()
atypestr := strings.ToLower(string(atype))
u := fmt.Sprintf("%s/sessions/%s/scope/%s", c.base, sessionID, atypestr)
resp, err := amasshttp.RequestWebPage(ctx, c.httpClient, &amasshttp.Request{URL: u})
if err != nil {
return nil, err
}View on GitHub (pinned to 79299dce87)
Solutions
- Read the 'error=' text - it is the server's specific reason; for 'not found' re-create the session or pick a live token from ListSessions
- For 401/403, fix the server's auth configuration or the client's credentials
- For 5xx errors, retry with backoff and check server logs
- Confirm the token belongs to the server instance you are querying
- Add a HealthCheck gate before stats polling loops so a down server is detected early
Example fix
// before: polling stats without handling dead sessions
for {
st, err := client.SessionStats(ctx, token)
if err != nil {
log.Print(err) // loops forever on 404
}
}
// after: recreate the session when the server says it is gone
st, err := client.SessionStats(ctx, token)
if err != nil && strings.Contains(err.Error(), "404") {
token, err = client.CreateSession(ctx, cfg)
if err == nil {
st, err = client.SessionStats(ctx, token)
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: validate token is live before requesting stats
tokens, err := c.ListSessions(ctx)
if err != nil {
return err
}
live := false
for _, t := range tokens {
if t == token {
live = true
break
}
}
if !live {
return fmt.Errorf("session %s is not active; recreate before querying stats", token)
} Try / catch
// Go
st, err := c.SessionStats(ctx, token)
if err != nil {
msg := err.Error()
switch {
case strings.Contains(msg, "404"):
// server told us the session is gone - recreate
token, err = c.CreateSession(ctx, cfg)
if err == nil {
st, err = c.SessionStats(ctx, token)
}
case strings.Contains(msg, "401"), strings.Contains(msg, "403"):
err = fmt.Errorf("auth rejected stats request: %w", err)
default:
err = backoffRetryStats(ctx, c, token)
}
} Prevention
- Always read the 'error=' suffix - the server explains the rejection
- Handle session expiry proactively in long-running pollers (recreate on 404)
- Keep auth configuration correct on the server side
- Retry only transient 5xx statuses, with capped backoff
When it happens
Trigger: Calling SessionStats(ctx, token) (or getStats) when the server rejects the request with a JSON error body: unknown or expired session token (404 with JSON message), auth rejection (401/403), or internal server error while computing stats (500).
Common situations: Session expired between TerminateSession/CreateSession cycles; token from a different engine instance; server-side auth misconfiguration; transient 500 while the server aggregates stats.
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
- listSessions: status=%s error=%s
- terminateSession: status=%s
- terminateSession: status=%s error=%s
- %s/stats: status=%s
- GLEIFSearchFuzzyCompletions: %s
AI-assisted analysis of owasp-amass/amass@79299dce87 (2026-09-06).
Data as JSON: /api/errors/55a969c433a60f37.
Report an issue: GitHub.