{"record":{"id":"95392071343ee009","repo":"xai-org/x-algorithm","slug":"ais-rejected-action-name-message","errorCode":null,"errorMessage":"AIS rejected {action_name}: {message}","messagePattern":"AIS rejected (.+?): (.+?)","errorType":"error_code","errorClass":"PermanentAisFailure","httpStatus":null,"severity":"error","filePath":"abuse-enforcement-service/service-lib/src/service.rs","lineNumber":928,"sourceCode":"pub struct PermanentAisFailure(pub String);\n\nimpl std::fmt::Display for PermanentAisFailure {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"permanent AIS rejection: {}\", self.0)\n    }\n}\n\nimpl std::error::Error for PermanentAisFailure {}\n\nconst DETERMINISTIC_AIS_EXCEPTION_CLASSES: &[&str] = &[\n    \"com.twitter.gizmoduck.thriftscala.ValidationFailed\",\n];\n\npub fn classify_ais_failure(action_name: &str, message: &str, resp: &Value) -> anyhow::Error {\n    if resp.pointer(\"/success/outcome/failure\").is_some()\n        || resp.pointer(\"/outcome/failure\").is_some()\n    {\n        return anyhow::Error::new(PermanentAisFailure(format!(\n            \"AIS rejected {action_name}: {message}\"\n        )));\n    }\n    if let Some(class) = resp\n        .pointer(\"/aisException/underlyingDetails/exceptionClass\")\n        .and_then(Value::as_str)\n        && DETERMINISTIC_AIS_EXCEPTION_CLASSES.contains(&class)\n    {\n        let detail = resp\n            .pointer(\"/aisException/underlyingDetails/message\")\n            .and_then(Value::as_str)\n            .unwrap_or(\"\");\n        return anyhow::Error::new(PermanentAisFailure(format!(\n            \"AIS {action_name} raised deterministic {class}: {detail}\"\n        )));\n    }\n    anyhow::anyhow!(\"AIS failure on {action_name}: {message}\")\n}","sourceCodeStart":910,"sourceCodeEnd":946,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/abuse-enforcement-service/service-lib/src/service.rs#L910-L946","documentation":"The Abuse Intervention Service (AIS) response contains an outcome/failure marker, meaning AIS definitively rejected the action. classify_ais_failure wraps this in a PermanentAisFailure because rejection outcomes are not retryable — retrying the same action will fail again.","triggerScenarios":"Calling an AIS enforcement action (via classify_ais_response) where the JSON response has /success/outcome/failure or /outcome/failure, e.g. invalid entity, policy forbids the action, or the action was already applied.","commonSituations":"Passing a malformed action ID or forbidden enforcement action; attempting to enforce on an entity AIS doesn't support; duplicate submission of an already-enforced decision.","solutions":["Inspect the {message} field to see the AIS rejection reason","Fix the action payload (valid action name, entity ID, params) per AIS docs","Do not retry — this failure is classified permanent; surface it to the caller or alerting","If rejection is unexpected, verify the AIS policy configuration for your service"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let err = classify_ais_response(...); if err.downcast_ref::<PermanentAisFailure>().is_some() { /* dead-letter, no retry */ } else { /* retry with backoff */ }","preventionTips":["Validate action payloads against AIS schema before submission","Distinguish permanent vs transient failures before configuring retry policy"],"tags":["abuse-enforcement","ais","permanent-failure"],"backgroundTag":"api-request-rejected-permanent","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}