nikivdev/code · error · anyhow::Error
pass either a subcommand or a bare import path, not both
Error message
pass either a subcommand or a bare import path, not both
What it means
The `f ext` dispatcher supports two mutually exclusive invocation styles: a subcommand (list/doctor/enable/disable/init/import) or a bare import path argument. Passing both in one command is ambiguous, so `run` bails immediately with this usage error before executing anything.
Source
Thrown at src/ext.rs:22
use std::process::Command;
use crate::cli::{ExtAction, ExtCommand};
use crate::code;
use crate::config;
use crate::flow_config;
use crate::setup::add_gitignore_entry;
use anyhow::{Context, Result, bail};
pub fn run(cmd: ExtCommand) -> Result<()> {
match (cmd.action, cmd.path) {
(Some(ExtAction::List { json }), None) => list_extensions(json),
(Some(ExtAction::Doctor { json }), None) => doctor_extensions(json),
(Some(ExtAction::Enable { name }), None) => enable_extension(&name),
(Some(ExtAction::Disable { name }), None) => disable_extension(&name),
(Some(ExtAction::Init { name, force }), None) => init_extension(&name, force),
(Some(ExtAction::Import { path }), None) => import_external_path(&path),
(None, Some(path)) => import_external_path(&path),
(Some(_), Some(_)) => bail!("pass either a subcommand or a bare import path, not both"),
(None, None) => list_extensions(false),
}
}
fn list_extensions(as_json: bool) -> Result<()> {
let extensions = flow_config::discover_extensions()?;
if as_json {
println!("{}", serde_json::to_string_pretty(&extensions)?);
return Ok(());
}
if extensions.is_empty() {
println!(
"No Flow extensions discovered. Create one with `f ext init <name>` under {}",
flow_config::flow_root_dir().join("extensions").display()
);
return Ok(());
}View on GitHub (pinned to a747e741ae)
Solutions
- Use one form only: `f ext import <path>` OR `f ext <path>` — not both
- Drop the subcommand if you intended the shortcut: `f ext ./my-extension`
- Drop the bare path if you intended the subcommand: `f ext import ./my-extension`
- Check any wrapper script/alias that might append an extra positional argument
Example fix
// before f ext import ./my-ext ./my-ext # subcommand AND bare path // after f ext import ./my-ext # or: f ext ./my-ext
Defensive patterns
Strategy: validation
Validate before calling
// validate CLI args before dispatching to `f ext`
let args: Vec<String> = std::env::args().skip(1).collect();
let subcommands = ["list", "doctor", "enable", "disable", "init", "import"];
let has_sub = args.first().map_or(false, |a| subcommands.contains(&a.as_str()));
let has_bare_path = args.len() > 1 && !subcommands.contains(&args[1].as_str());
if has_sub && has_bare_path {
bail!("pass either a subcommand or a bare import path, not both");
} Prevention
- Pick one invocation form: subcommand OR bare path, never both
- Check wrapper scripts/aliases don't append extra positionals
- Consult `f ext --help` for accepted forms
- Update old scripts that predate the bare-path shortcut
When it happens
Trigger: `f ext <subcommand> <path>` — the parser matched both an ExtAction (e.g. Import { path }) and a bare path positional, hitting the (Some(_), Some(_)) arm at src/ext.rs:22.
Common situations: Habit from other CLIs where subcommand plus positional is normal; copying an example that used the bare-path form but prepending a subcommand anyway; shell completion or wrapper script injecting an extra argument.
Related errors
- No prompt provided. Usage: f agents run {} "your prompt here
- missing prompt. Usage: f ai everruns "your prompt"
- Usage: f migrate <target> OR f migrate <source> <target> OR
- No command specified
- Usage: f hash <paths or unhash args>
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/da88a30e14ad8866.
Report an issue: GitHub.