espanso/espanso · critical

missing cli_args in worker main

Error message

missing cli_args in worker main

What it means

Immediately after paths, worker_main does args.cli_args.expect("missing cli_args in worker main"). The parsed clap arguments are attached by the dispatcher; the expect panics when cli_args was never populated. Like the missing-paths check, this is an internal contract violation of the CliModuleArgs wiring rather than a user-recoverable condition.

Source

Thrown at espanso/src/cli/worker/mod.rs:66

pub fn new() -> CliModule {
    #[allow(clippy::needless_update)]
    CliModule {
        requires_paths: true,
        requires_config: true,
        requires_linux_capabilities: true,
        enable_logs: true,
        log_mode: super::LogMode::AppendOnly,
        subcommand: "worker".to_string(),
        entry: worker_main,
        ..Default::default()
    }
}

fn worker_main(args: CliModuleArgs) -> i32 {
    prevent_running_as_root_on_macos();

    let paths = args.paths.expect("missing paths in worker main");
    let cli_args = args.cli_args.expect("missing cli_args in worker main");

    // When restarted, the daemon passes the reason why the worker was restarted (config_change, etc)
    let start_reason = cli_args.value_of("start-reason").map(String::from);
    debug!("starting with start-reason = {start_reason:?}");

    // Avoid running multiple worker instances
    let lock_file = acquire_worker_lock(&paths.runtime);
    if lock_file.is_none() {
        error!("worker is already running!");
        return WORKER_ALREADY_RUNNING;
    }

    let config_store = args
        .config_store
        .expect("missing config store in worker main");
    let match_store = args
        .match_store
        .expect("missing match store in worker main");

View on GitHub (pinned to e6c3736675)

Solutions

  1. Make the dispatcher assign args.cli_args from the parsed clap matches before calling worker_main.
  2. Keep dispatch code in sync with the espanso version — re-apply local patches to the current dispatch flow.
  3. Invoke espanso through its normal CLI entry point rather than calling worker_main directly.
  4. Convert the expect into a clean error in custom builds.

Example fix

// before
let cli_args = args.cli_args.expect("missing cli_args in worker main");

// after
let cli_args = args.cli_args.ok_or_else(|| anyhow::anyhow!(
    "missing cli_args in worker main: dispatcher did not pass parsed arguments"
))?;
Defensive patterns

Strategy: type-guard

Type guard

fn require_cli_args(args: &CliModuleArgs) -> Result<&ArgMatches, String> {
    args.cli_args.as_ref().ok_or_else(|| "missing cli_args in worker main".to_string())
}

Try / catch

let cli_args = args.cli_args.ok_or_else(|| anyhow::anyhow!("missing cli_args in worker main"))?;

Prevention

When it happens

Trigger: worker_main called by the dispatch layer without first assigning args.cli_args from the parsed clap matches (wiring bug or custom entry point).

Common situations: Forked/patched builds with altered CLI dispatch; new subcommand plumbing that forgot to pass matches through; direct programmatic invocation of worker_main.

Related errors


AI-assisted analysis of espanso/espanso@e6c3736675 (2026-09-06). Data as JSON: /api/errors/e76c07f1dc6a45ff. Report an issue: GitHub.