owasp-amass/amass · error
%s/stats: status=%s
Error message
%s/stats: status=%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 not a decodable JSON error, so only the session token and HTTP status are reported. The format is '<token>/stats: status=<status>'. It indicates statistics could not be retrieved for that session.
Source
Thrown at engine/api/client/v1/client.go:178
return fmt.Errorf("terminateSession: status=%s", resp.Status)
}
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 {View on GitHub (pinned to 79299dce87)
Solutions
- Check the status in the message: 404 usually means the session no longer exists - call ListSessions to confirm and obtain a live token
- If the status is 502/503, verify the engine server is running (HealthCheck) and restart if needed
- Ensure the token was created by the same server instance (CreateSession) and has not been terminated
- Verify the NewClient base URL points at the engine API root
- Capture the raw response to identify non-JSON bodies (proxy HTML) and fix the intervening infrastructure
Example fix
// before: using a token cached from a previous run
st, err := client.SessionStats(ctx, cachedToken)
// after: fall back to a live session token
tokens, err := client.ListSessions(ctx)
if err != nil || len(tokens) == 0 {
token, err = client.CreateSession(ctx, cfg)
} else {
token = tokens[0]
}
st, err = client.SessionStats(ctx, token) Defensive patterns
Strategy: try-catch
Validate before calling
// Go: confirm the session exists before polling stats
func ensureSession(ctx context.Context, c *v1.Client, token uuid.UUID, cfg *config.Config) (uuid.UUID, error) {
tokens, err := c.ListSessions(ctx)
if err != nil {
return uuid.UUID{}, err
}
for _, t := range tokens {
if t == token {
return token, nil
}
}
return c.CreateSession(ctx, cfg)
} Try / catch
// Go
st, err := c.SessionStats(ctx, token)
if err != nil {
msg := err.Error()
if strings.Contains(msg, "404") {
return nil, fmt.Errorf("session %s no longer exists; recreate it", token)
}
if strings.Contains(msg, "502") || strings.Contains(msg, "503") {
return backoffRetryStats(ctx, c, token)
}
return nil, err
} Prevention
- Verify tokens against ListSessions before using them after any restart
- Gate stats polling with HealthCheck
- Use a single engine instance for create/stats/terminate to avoid token mismatch
- If messages lack 'error=', check for proxies returning HTML error pages and bypass or fix them
When it happens
Trigger: Calling SessionStats(ctx, token) (directly or via getStats) when the server returns a non-200 with a non-JSON body: the token refers to a session that has expired or been terminated (404), the request is rejected by auth middleware, a proxy serves an HTML error page (502/503), or the server returns an empty body on failure.
Common situations: Querying stats for a session terminated earlier in the run; stale token after an engine restart (in-memory sessions lost); load balancer or ingress returning non-JSON error pages; wrong base URL causing route misses.
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 error=%s
- GLEIFSearchFuzzyCompletions: %s
AI-assisted analysis of owasp-amass/amass@79299dce87 (2026-09-06).
Data as JSON: /api/errors/3b2c12a89cbba1d1.
Report an issue: GitHub.