jdx/mise · error

required source is not a regular file

Error message

required source is not a regular file: {}

What it means

Thrown in sources() preflight when a source file required by the batch resolves in the incoming plans to a git object whose mode is not a regular/executable file (100644/100755). The required dependency must be a real file; symlinks and gitlinks are rejected.

Solutions

  1. Replace the symlink/submodule with a regular file at the required source path in the shared repo and commit
  2. Remove the path from the setup's required sources if it is not actually needed
  3. Re-pull after the upstream fix

Example fix

# before
ln -s templates/env.sh required/env.sh && git add required/env.sh
# after
cp templates/env.sh required/env.sh && git add required/env.sh
Defensive patterns

Strategy: validation

Validate before calling

for src in "${required_sources[@]}"; do
  mode=$(git ls-tree HEAD -- "$src" | awk '{print $1}')
  [[ "$mode" == 100644 || "$mode" == 100755 ]] || echo "$src is not a regular file"
done

Prevention

When it happens

Trigger: A required source path has an incoming plan whose apply entry records mode 120000 (symlink) or 160000 (gitlink); sources() cat-checks the blob after the mode test fails.

Common situations: Shared setup commits a symlink where a required source file should be; submodule accidentally created at a source path.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at src/system/history/sync/preflight.rs:142

    // The repository inventory, not a source or output mentioned by incoming
    // configuration, determines which files the batch may install.
    let mut prospective = tracked.clone();
    prospective.required_sources = declarations.required_sources;
    Ok(prospective)
}

/// Required source files must exist in the complete proposed write set or
/// already be available locally. A queued deletion is not an available source.
pub(super) fn sources(repo: &HistoryRepo, tracked: &TrackedSet, plans: &[PathPlan]) -> Result<()> {
    let roots = Roots::current();
    for source in &tracked.required_sources {
        let planned = plans
            .iter()
            .find(|plan| roots.locate(&plan.branch_path).path() == Some(source.as_path()));
        match planned.and_then(|plan| plan.apply.as_ref()) {
            Some(Some((mode, oid))) => {
                if mode != "100644" && mode != "100755" {
                    bail!(
                        "required source is not a regular file: {}",
                        source.display()
                    );
                }
                repo.cat_object(oid)?;
            }
            Some(None) => bail!(
                "incoming setup deletes required source {}",
                source.display()
            ),
            None if !source.exists() && !has_incoming_child(&roots, source, plans) => {
                bail!(
                    "incoming setup is missing required source {}",
                    source.display()
                );
            }
            None => {}
        }

View on GitHub (pinned to 533346cc37)