{"record":{"id":"70a8e2eb3c77cff7","repo":"owasp-amass/amass","slug":"terminatesession-status-s-error-s","errorCode":null,"errorMessage":"terminateSession: status=%s error=%s","messagePattern":"terminateSession: status=(.+?) error=(.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/api/client/v1/client.go","lineNumber":162,"sourceCode":"\treturn tokens, nil\n}\n\n// Terminates the session associated with the provided token.\nfunc (c *Client) TerminateSession(ctx context.Context, token uuid.UUID) error {\n\tresp, err := amasshttp.RequestWebPage(ctx, c.httpClient, &amasshttp.Request{\n\t\tMethod: http.MethodDelete,\n\t\tURL:    c.base + \"/sessions/\" + token.String(),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif resp.StatusCode != http.StatusNoContent {\n\t\tmsg, err := readJSONError(resp.Body)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"terminateSession: status=%s\", resp.Status)\n\t\t}\n\t\treturn fmt.Errorf(\"terminateSession: status=%s error=%s\", resp.Status, msg)\n\t}\n\treturn nil\n}\n\n// Retrieves statistics for the session associated with the provided token.\nfunc (c *Client) SessionStats(ctx context.Context, token uuid.UUID) (*et.SessionStats, error) {\n\tresp, err := amasshttp.RequestWebPage(ctx, c.httpClient,\n\t\t&amasshttp.Request{URL: c.base + \"/sessions/\" + token.String() + \"/stats\"})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tmsg, err := readJSONError(resp.Body)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%s/stats: status=%s\", token.String(), resp.Status)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s/stats: status=%s error=%s\", token.String(), resp.Status, msg)","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/owasp-amass/amass/blob/79299dce87b0085db0f2f4ef3e9c52cccb49f514/engine/api/client/v1/client.go#L144-L180","documentation":"Returned by Client.TerminateSession when DELETE /api/v1/sessions/{token} returns a status other than 204 and the response body IS a decodable JSON error, so the message includes the server's own error text after 'error='. It reports both the HTTP status and the reason the server refused to terminate the session.","triggerScenarios":"Calling TerminateSession(ctx, token) when the server actively rejects the delete with a JSON error body: the session token does not exist (404 with a JSON error message), malformed/unknown token format rejected by routing, the server refuses due to auth (401/403) and returns a JSON error, or an internal failure while removing the session (500).","commonSituations":"Token already terminated by another client or process; token copied from a different engine instance; server-side permission config blocking the DELETE; transient internal error during session cleanup.","solutions":["Read the 'error=' portion of the message - it is the server's own reason and usually names the exact problem (e.g. session not found)","For 'not found' errors, skip termination: the session is already gone, or re-list via ListSessions to get valid tokens","For 401/403, fix server auth/permissions or the client's credentials","Verify the token originates from the same server instance you are calling (CreateSession/ListSessions on this client)","Retry with backoff for 5xx responses"],"exampleFix":"// before: assuming any terminate error means retry\nif err := client.TerminateSession(ctx, token); err != nil {\n    retry(token)\n}\n\n// after: treat 404-style 'not found' errors as success\nif err := client.TerminateSession(ctx, token); err != nil {\n    if strings.Contains(err.Error(), \"404\") {\n        return nil // already terminated\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// Go: only terminate tokens from this server\ntokens, err := c.ListSessions(ctx)\nif err != nil {\n    return err\n}\nvalid := false\nfor _, t := range tokens {\n    if t == token {\n        valid = true\n    }\n}\nif !valid {\n    return fmt.Errorf(\"token %s not managed by this server\", token)\n}","typeGuard":null,"tryCatchPattern":"// Go\nif err := c.TerminateSession(ctx, token); err != nil {\n    msg := err.Error()\n    switch {\n    case strings.Contains(msg, \"404\"):\n        log.Printf(\"session %s already terminated\", token)\n        return nil\n    case strings.Contains(msg, \"401\"), strings.Contains(msg, \"403\"):\n        return fmt.Errorf(\"auth failure terminating session: %w\", err)\n    default:\n        return backoffRetry(func() error { return c.TerminateSession(ctx, token) })\n    }\n}","preventionTips":["Parse the 'error=' portion of the message - it names the server-side cause","Never reuse tokens from a previous engine instance or run","Fix server auth config if 401/403 recur","Only retry on 5xx; 4xx responses are deterministic"],"tags":["http","api","network","amass"],"backgroundTag":"http-error-response","analyzedSha":"79299dce87b0085db0f2f4ef3e9c52cccb49f514","analyzedAt":"2026-09-06T08:22:48.198Z","contentChangedAt":"2026-09-06T08:22:48.198Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}