{"record":{"id":"5083d18d985bb520","repo":"zed-industries/zed","slug":"missing-auto-resolution-outcomes","errorCode":null,"errorMessage":"missing auto-resolution outcomes","messagePattern":"missing auto-resolution outcomes","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/agent/src/thread.rs","lineNumber":6454,"sourceCode":"                        context,\n                        kind: acp_thread::AuthorizationKind::PermissionGrant,\n                    },\n                )))\n            {\n                log::error!(\"Failed to send tool call authorization: {error}\");\n                return Err(anyhow!(\"Failed to send tool call authorization: {error}\"));\n            }\n\n            let Some(check_settings) = check_settings else {\n                let outcome = response_rx\n                    .await\n                    .map_err(|_| anyhow!(\"authorization channel closed\"))?;\n                ensure_tool_call_authorization_not_interrupted(&outcome)?;\n\n                return Self::persist_permission_outcome(&outcome, fs, cx);\n            };\n            let Some((auto_allow_outcome, auto_deny_outcome)) = auto_resolution_outcomes else {\n                return Err(anyhow!(\"missing auto-resolution outcomes\"));\n            };\n\n            let (mut settings_tx, mut settings_rx) = watch::channel(());\n            let _settings_subscription = cx.update(|cx| {\n                cx.observe_global::<SettingsStore>(move |_cx| {\n                    settings_tx.send(()).ok();\n                })\n            });\n\n            // Race the user's response against settings changes. On each\n            // settings change, re-evaluate `check_settings`: if it now\n            // yields a definitive Allow or Deny, resolve the prompt\n            // without user interaction. Otherwise keep waiting on the\n            // same prompt.\n            loop {\n                let settings_changed = async {\n                    if settings_rx.changed().await.is_err() {\n                        std::future::pending::<()>().await;","sourceCodeStart":6436,"sourceCodeEnd":6472,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/agent/src/thread.rs#L6436-L6472","documentation":"Internal invariant error in the agent thread's permission flow: settings-based auto-resolution is active (`check_settings` is Some) but `auto_resolution_outcomes` — the canned Allow/Deny outcomes used to auto-resolve the prompt — is None. The two arguments must be supplied together; this error means a caller violated that contract. It is a programming error, not a runtime condition.","triggerScenarios":"Invoking the authorization helper with a `check_settings` callback but `auto_resolution_outcomes: None` — e.g. a new call site enabled settings checking without providing outcomes, or a refactor dropped the tuple while keeping the callback.","commonSituations":"Refactors of the permission flow; new permission modes added without updating every caller; custom agent-thread setups that hand-roll the arguments.","solutions":["Fix the call site: pass `auto_resolution_outcomes` whenever `check_settings` is Some.","Make the invariant unrepresentable: bundle the callback and its outcomes in a single struct passed as one Option.","Add a debug_assert at function entry so mismatches fail loudly in tests."],"exampleFix":"// before\nfn authorize(\n    check_settings: Option<CheckFn>,\n    auto_resolution_outcomes: Option<(Outcome, Outcome)>, // can diverge from check_settings\n)\n// after\nstruct AutoResolution<CheckFn> {\n    check: CheckFn,\n    allow_outcome: Outcome,\n    deny_outcome: Outcome,\n}\nfn authorize(auto_resolution: Option<AutoResolution<CheckFn>>) // paired or absent, never half","handlingStrategy":"validation","validationCode":"// Enforce the pairing at the call boundary:\nlet (check_settings, auto_resolution_outcomes) = match auto_resolution {\n    Some(ar) => (Some(ar.check), Some((ar.allow_outcome, ar.deny_outcome))),\n    None => (None, None),\n};\ndebug_assert_eq!(\n    check_settings.is_some(),\n    auto_resolution_outcomes.is_some(),\n    \"check_settings requires auto_resolution_outcomes\"\n);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Bundle the settings callback and its outcomes in one struct so they cannot diverge.","Add a debug_assert for the invariant at function entry.","When adding new permission modes, update every caller in the same change."],"tags":["agent","permissions","invariant","internal"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}