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

  1. Check the status in the message: 404 usually means the session no longer exists - call ListSessions to confirm and obtain a live token
  2. If the status is 502/503, verify the engine server is running (HealthCheck) and restart if needed
  3. Ensure the token was created by the same server instance (CreateSession) and has not been terminated
  4. Verify the NewClient base URL points at the engine API root
  5. 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

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


AI-assisted analysis of owasp-amass/amass@79299dce87 (2026-09-06). Data as JSON: /api/errors/3b2c12a89cbba1d1. Report an issue: GitHub.