ansible/ansible · error · ValueError

%s is not a directory

Error message

%s is not a directory

What it means

Raised by AnsibleModule's git module helper (get_repo_path) after parsing a '.git' file that contains a 'gitdir: <path>' pointer. The pointer is resolved either as an absolute path or relative to the destination directory; if the resolved path is not an existing directory, this ValueError fires. It almost always indicates a broken or stale submodule/worktree checkout where the .git file points at a missing .git dir.

Source

Thrown at lib/ansible/modules/git.py:851

    else:
        repo_path = os.path.join(dest, '.git')
    # Check if the .git is a file. If it is a file, it means that the repository is in external directory respective to the working copy (e.g. we are in a
    # submodule structure).
    if os.path.isfile(repo_path):
        with open(repo_path, 'r') as gitfile:
            data = gitfile.read()
        ref_prefix, gitdir = data.rstrip().split('gitdir: ', 1)
        if ref_prefix:
            raise ValueError('.git file has invalid git dir reference format')

        # There is a possibility the .git file to have an absolute path.
        if os.path.isabs(gitdir):
            repo_path = gitdir
        else:
            # Use original destination directory with data from .git file.
            repo_path = os.path.join(dest, gitdir)
        if not os.path.isdir(repo_path):
            raise ValueError('%s is not a directory' % repo_path)
    return repo_path


def get_head_branch(git_path, module, dest, remote, bare=False):
    """
    Determine what branch HEAD is associated with.  This is partly
    taken from lib/ansible/utils/__init__.py.  It finds the correct
    path to .git/HEAD and reads from that file the branch that HEAD is
    associated with.  In the case of a detached HEAD, this will look
    up the branch in .git/refs/remotes/<remote>/HEAD.
    """
    try:
        repo_path = get_repo_path(dest, bare)
    except (OSError, ValueError) as ex:
        # No repo path found
        # ``.git`` file does not have a valid format for detached Git dir.
        module.fail_json(
            msg='Current repo does not have a valid reference to a '

View on GitHub (pinned to 9cf16a4aca)

Solutions

  1. Inspect the .git file inside dest and confirm the path after 'gitdir: ' exists on the managed host
  2. If it is a submodule, re-run git submodule update --init or use the git module with the correct parent repo dest
  3. Re-clone the repository (delete dest or set force/version tweaks) so the .git linkage is regenerated
  4. If the gitdir is legitimately elsewhere, make the reference an absolute path that is valid on the target machine

Example fix

# before (dangling submodule pointer in dest/.git)
# gitdir: ../.git/modules/mylib   <- directory does not exist

# after: re-init submodule from the superproject
git submodule update --init --recursive
# or re-clone:
ansible.builtin.git:
  repo: https://example.com/repo.git
  dest: /srv/checkout
  force: true
Defensive patterns

Strategy: validation

Validate before calling

import os

def gitdir_resolves(dest):
    """True if dest/.git is absent, a dir, or a file whose gitdir: target exists."""
    dotgit = os.path.join(dest, '.git')
    if not os.path.exists(dotgit):
        return False
    if os.path.isdir(dotgit):
        return True
    with open(dotgit) as f:
        data = f.read()
    _, gitdir = data.rstrip().split('gitdir: ', 1)
    repo = gitdir if os.path.isabs(gitdir) else os.path.join(dest, gitdir)
    return os.path.isdir(repo)

Try / catch

try:
    repo_path = get_repo_path(dest)
except ValueError as e:
    fail_json(msg=str(e), hint='Check .git gitdir reference for submodules/worktrees')

Prevention

When it happens

Trigger: Running the git module with a dest that is a submodule or linked worktree whose .git file references a gitdir (e.g. ../.git/modules/name) that does not exist on disk; a partially cloned/updated repo; a copied/moved checkout where the relative gitdir path no longer resolves.

Common situations: Submodules cloned shallowly or with update=none leaving dangling .git files; manually moving a worktree directory; interrupted git submodule update; NFS/relative path mismatches when dest differs from the original clone location.

Related errors


AI-assisted analysis of ansible/ansible@9cf16a4aca (2026-08-15). Data as JSON: /api/errors/ec86f43eb76d47e5. Report an issue: GitHub.