{"record":{"id":"e5238b0f6d1e0a0d","repo":"astrid-runtime/astrid","slug":"exactly-one-of-as-fleet-or-admin-is-requir","errorCode":null,"errorMessage":"exactly one of --as, --fleet, or --admin is required","messagePattern":"exactly one of --as, --fleet, or --admin is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/storage.rs","lineNumber":87,"sourceCode":"    /// Native mount point or Windows drive target.\n    #[arg(value_name = \"MOUNTPOINT\")]\n    mountpoint: PathBuf,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum MountView {\n    Principal(PrincipalId),\n    Fleet(FleetUid),\n    Admin,\n}\n\nimpl MountArgs {\n    fn view(&self) -> Result<MountView> {\n        match (&self.as_principal, self.fleet, self.admin) {\n            (Some(principal), None, false) => Ok(MountView::Principal(principal.clone())),\n            (None, Some(fleet), false) => Ok(MountView::Fleet(fleet)),\n            (None, None, true) => Ok(MountView::Admin),\n            _ => bail!(\"exactly one of --as, --fleet, or --admin is required\"),\n        }\n    }\n\n    fn access(&self, view: &MountView) -> &'static str {\n        if self.read_only || (matches!(view, MountView::Admin) && !self.read_write) {\n            \"read-only\"\n        } else {\n            \"read-write\"\n        }\n    }\n}\n\n/// Run a storage command through the platform's lifecycle-independent provider.\npub(crate) fn run(command: StorageCommand) -> Result<ExitCode> {\n    let provider_name = platform_provider_name();\n    let provider = crate::bootstrap::find_coinstalled_companion_binary(provider_name)\n        .with_context(|| {\n            format!(","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/storage.rs#L69-L105","documentation":"The storage mount `view` command resolves its principal scope from exactly one of three flags: --as (a principal), --fleet (a fleet id), or --admin. MountArgs::view maps the flag combination to a MountView and bails when zero flags or more than one flag is supplied. The mount must be unambiguously scoped to a single identity.","triggerScenarios":"Calling `astrid storage mount`/`view` with no scoping flag, with two or more of --as/--fleet/--admin together, or with --admin combined with --read-write in a way that falls through to the catch-all (any non-exact combination hits the bail).","commonSituations":"Copy-pasted command lines that keep a stale flag; scripts adding --admin for convenience alongside --as; forgetting which flag the subcommand requires.","solutions":["Pass exactly one of: `--as <principal>`, `--fleet <id>`, or `--admin`.","Remove any duplicate/scoped flags from the command line or script.","Check `astrid storage mount --help` for the accepted flag combinations."],"exampleFix":"// before\nastrid storage mount --as alice --fleet eng\n# error: exactly one of --as, --fleet, or --admin is required\n\n// after\nastrid storage mount --as alice","handlingStrategy":"validation","validationCode":"fn scoped_flags_ok(as_: &Option<String>, fleet: &Option<String>, admin: bool) -> bool {\n    let count = as_.is_some() as usize + fleet.is_some() as usize + admin as usize;\n    count == 1\n}","typeGuard":null,"tryCatchPattern":"match mount_args.view() {\n    Err(e) if e.to_string().contains(\"exactly one of\") => {\n        eprintln!(\"Pass exactly one of --as, --fleet, or --admin.\");\n    }\n    other => other?,\n}","preventionTips":["Build mount commands with exactly one scoping flag.","In scripts, use shell parameter expansion to strip stale flags when switching scope.","Review `astrid storage mount --help` before composing new invocations."],"tags":["cli","storage","mount","argument-validation"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}