{"record":{"id":"5961c7908d82a01b","repo":"Hmbown/CodeWhale","slug":"permission-rule-action-does-not-match-requested-persistence","errorCode":null,"errorMessage":"permission rule action does not match requested {:?} persistence","messagePattern":"permission rule action does not match requested (.+?) persistence","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/lib.rs","lineNumber":5368,"sourceCode":"                && codewhale_execpolicy::normalize_workspace_relative_path(path, &workspace)\n                    .is_none_or(|path| path.is_empty())\n            {\n                bail!(\"persistent path allow rules must stay within the workspace\");\n            }\n        }\n        self.append_permission_rules(rules, PermissionAction::Allow)\n    }\n\n    fn append_permission_rules(\n        &mut self,\n        rules: &[ToolAskRule],\n        expected_action: PermissionAction,\n    ) -> Result<usize> {\n        if rules.is_empty() {\n            return Ok(0);\n        }\n        if rules.iter().any(|rule| rule.action != expected_action) {\n            bail!(\n                \"permission rule action does not match requested {:?} persistence\",\n                expected_action\n            );\n        }\n\n        let path = checked_permissions_path_for_config_path(&self.path)?;\n        let (added, persisted) = config_document::with_config_write_lock(&path, |path| {\n            let (_, raw, mut permissions) = read_permissions_state(path)?;\n            let mut document = parse_permissions_document(path, &raw)?;\n\n            if !document.contains_key(\"rules\") {\n                document[\"rules\"] = toml_edit::Item::ArrayOfTables(toml_edit::ArrayOfTables::new());\n            }\n            let rules_item = document\n                .get_mut(\"rules\")\n                .expect(\"rules entry was inserted above\");\n\n            let mut added = 0;","sourceCodeStart":5350,"sourceCodeEnd":5386,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/lib.rs#L5350-L5386","documentation":"When appending permission rules under a requested persistence mode, every rule in the batch must already carry the action (`Allow`/`Ask`/etc.) matching that mode. A mixed or mismatched batch indicates a caller bug, so the whole write is aborted rather than persisting rules under the wrong action.","triggerScenarios":"Calling `append_permission_rules` (or the allow/ask wrappers around it) with a batch where at least one rule's `action` field differs from the `expected_action` parameter for the requested persistence kind.","commonSituations":"Batching rules collected from different sources (some Allow, some Ask) into one persistence call; copying a rule from an Ask list into an Allow append; a refactor changing the expected action without updating rule construction.","solutions":["Filter the batch to only rules whose `action` equals the requested action before appending","Set each rule's `action` to the requested action when constructing the batch","Split the batch into separate calls per action/persistence kind"],"exampleFix":"// before\nrules.push(PermissionRule { action: PermissionAction::Ask, .. });\nappend_permission_rules(&rules, PermissionAction::Allow);\n// after\nrules.push(PermissionRule { action: PermissionAction::Allow, .. });\nappend_permission_rules(&rules, PermissionAction::Allow);","handlingStrategy":"validation","validationCode":"fn actions_match(rules: &[PermissionRule], expected: PermissionAction) -> bool {\n    rules.iter().all(|r| r.action == expected)\n}","typeGuard":null,"tryCatchPattern":"match config.append_permission_rules(&rules, expected_action) {\n    Err(e) if e.to_string().contains(\"does not match requested\") => {\n        // split batch by action or rewrite actions, then retry\n    }\n    result => result?,\n}","preventionTips":["Construct each batch from a single source so all actions agree","Assert batch action homogeneity before calling persistence APIs","Filter `rules.retain(|r| r.action == expected)` before appending"],"tags":["config","permissions","consistency"],"backgroundTag":"conflicting-config-options","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}