jdx/mise · error

cannot create nested task stubs because

Error message

cannot create nested task stubs because {} is not the generated stub for task {}

What it means

When migrating flat task stubs to nested ones, mise may need to replace a legacy stub path with a directory. If the legacy path exists as a regular file whose content is neither the current nor legacy generated stub output, mise refuses to overwrite a file it did not generate, protecting hand-written files from destruction.

Solutions

  1. Restore the legacy path's file content to the exact generated stub output (regenerate it with the old layout) so migration can proceed
  2. Delete or move the unrecognized file at the legacy path if it is not needed
  3. Check the file into a different location if it is hand-written, since mise will never overwrite non-generated files

Example fix

// before: hand-edited legacy stub
#!/bin/sh
mise x -- my-task "$@" # custom tweaks
// after: regenerate or remove so it matches stub output
rm .mise/tasks/build && mise generate task-stubs
Defensive patterns

Strategy: validation

Validate before calling

const legacy = fs.readFileSync(legacyStubPath, 'utf8');
if (legacyStubExists && legacy !== generatedOutput && legacy !== legacyOutput) {
  throw new Error(`${legacyStubPath} was modified by hand; save it and remove before nested migration`);
}

Try / catch

try {
  execSync('mise generate task-stubs');
} catch (e) {
  if (String(e).includes('is not the generated stub for task')) {
    console.error('Back up the hand-edited legacy stub, delete it, rerun generation');
  }
}

Prevention

When it happens

Trigger: Running `mise generate task-stubs` where a task's legacy stub path (flat layout) exists as a file with user-modified or unrelated content, while the new layout places stubs in a directory of that name.

Common situations: Developers edited a previously generated stub by hand and later enabled nested task stubs; a checked-in script occupies the path that the nested stub directory needs; generated from an older mise version with different stub content.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/9f4910f2fb39bc9a. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/generate/task_stubs.rs:509

                display_path(path)
            );
        }
    }
    Ok(paths)
}

fn validate_stub_paths(
    dir: &Path,
    stubs: &[TaskStub<'_>],
    launchers: &Launchers,
) -> Result<Vec<StubMigration>> {
    let mut migrations = HashSet::new();
    for stub in stubs.iter().filter(|stub| stub.legacy_path != stub.path) {
        match fs::symlink_metadata(&stub.legacy_path) {
            Ok(metadata) if metadata.file_type().is_file() => {
                let existing = file::read_to_string(&stub.legacy_path)?;
                if existing != stub.output && existing != stub.legacy_output {
                    bail!(
                        "cannot create nested task stubs because {} is not the generated stub for task {}",
                        display_path(&stub.legacy_path),
                        stub.task.display_name
                    );
                }
                migrations.insert(StubMigration::File(stub.legacy_path.clone()));
            }
            Ok(metadata) if metadata.file_type().is_dir() => {}
            Ok(_) => bail!(
                "cannot create nested task stubs because {} is not a directory",
                display_path(&stub.legacy_path)
            ),
            Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
            Err(err) => return Err(err.into()),
        }
    }

    for stub in stubs {

View on GitHub (pinned to 533346cc37)