jdx/mise · error · eyre::Report

task {task_name} input group cycle: {}

Error message

task {task_name} input group cycle: {}

What it means

Thrown while mise expands task `inputs` entries that reference input groups (`@group:<name>`) in mise.toml. `expand_task_inputs` (src/config/mod.rs:2961) keeps a stack of group names currently being expanded; if the same group appears again deeper in the chain (a -> b -> a), expansion could never terminate, so mise bails and prints the full cycle path. This is task-configuration validation, not a failure of the task itself.

Source

Thrown at src/config/mod.rs:2988

    for entry in entries {
        let Some(group) = entry.strip_prefix(TASK_INPUT_GROUP_PREFIX) else {
            expanded.push(if anchor_literals {
                anchor_task_input(root, entry)
            } else {
                entry.clone()
            });
            continue;
        };
        let (groups, groups_root) = task_inputs.input_groups.as_ref().ok_or_else(|| {
            eyre!("task {task_name} references undefined input group {group:?} with {entry:?}")
        })?;
        let inputs = groups.get(group).ok_or_else(|| {
            eyre!("task {task_name} references undefined input group {group:?} with {entry:?}")
        })?;
        if let Some(cycle_start) = stack.iter().position(|name| name == group) {
            let mut cycle = stack[cycle_start..].to_vec();
            cycle.push(group.to_string());
            bail!(
                "task {task_name} input group cycle: {}",
                cycle.iter().join(" -> ")
            );
        }
        stack.push(group.to_string());
        expanded.extend(expand_task_inputs(
            inputs,
            task_inputs,
            groups_root,
            task_name,
            stack,
            true,
        )?);
        stack.pop();
    }
    Ok(expanded)
}

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Read the cycle in the message (e.g. `a -> b -> a`) and open the `[task_inputs.groups.*]` definitions in the config file being loaded
  2. Break the loop by removing the `@group:` reference that closes it (the edge back to the first group in the printed cycle)
  3. If two groups must share content, extract a third base group and have both include it instead of each other
  4. Re-run any task-loading command (e.g. `mise tasks ls`) to confirm the config now parses

Example fix

# before — cycle: shared -> lint -> shared
[task_inputs.groups.shared]
inputs = ["src/**", "@group:lint"]
[task_inputs.groups.lint]
inputs = ["@group:shared", "lint/**"]

# after — one-directional references only
[task_inputs.groups.base]
inputs = ["src/**"]
[task_inputs.groups.shared]
inputs = ["@group:base"]
[task_inputs.groups.lint]
inputs = ["@group:base", "lint/**"]
Defensive patterns

Strategy: validation

Validate before calling

# pre-commit lint: fail on input-group cycles before mise does
import tomllib, sys
cfg = tomllib.load(open("mise.toml", "rb"))
groups = cfg.get("task_inputs", {}).get("groups", {})
def dfs(g, stack):
    if g in stack:
        sys.exit(f"input group cycle: {' -> '.join(stack[stack.index(g):] + [g])}")
    for ref in groups.get(g, []):
        if isinstance(ref, str) and ref.removeprefix("@group:") in groups:
            dfs(ref.removeprefix("@group:"), stack + [g])
for g in groups:
    dfs(g, [])

Prevention

When it happens

Trigger: A task's `inputs` (or a group's member list) contains `@group:a`, group `a` includes `@group:b`, and group `b` includes `@group:a` again — directly or through more groups. The error fires only when a group name is already on the expansion stack; referencing a group once, or referencing it from two sibling groups, is fine.

Common situations: Refactoring shared input lists into groups and accidentally making two groups reference each other; renaming a group so an old name now resolves into a chain that loops back; copy-pasting a group definition and leaving a self/mutual reference; YAML anchors duplicating group references.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/1b8a2d4969f77979. Report an issue: GitHub.