GitHub Actions: "fatal: detected dubious ownership in repository"
Git refuses to use a repository whose directory belongs to another user. On a GitHub-hosted runner the checkout belongs to the runner's user, so this appears when a step runs git as someone else: root in a container, a Docker action, or a self-hosted runner's service account. actions/checkout sets the exception for itself only, so its own step passes and the next git command fails.
What it looks like
fatal: detected dubious ownership in repository at '/__w/octo-repo/octo-repo' To add an exception for this directory, call: git config --global --add safe.directory /__w/octo-repo/octo-repo Error: Process completed with exit code 128.
Other tools put it in their own words around the same line: gh says "failed to run git: fatal: detected dubious ownership", and Composer says the repository "does not have the correct ownership and git refuses to use it".
Why checkout does not cover the next step
set-safe-directory is on by default, but actions/checkout writes it to the global config of a temporary home directory. Its log says "Temporarily overriding HOME='…' before making global git config changes", and the source deletes that directory afterwards. Later steps use the real HOME, which has no exception (goabonga cloud #125, sast-benchmarks #18).
1. A job with container:
The workspace under /__w belongs to the runner's user, and most images run steps as root. In one pipeline nine container legs failed on git tag --list, and nine others in the same container passed only because they ran no git after checkout (goabonga cloud #125). Add the exception once, after checkout and before any git command:
jobs:
release:
runs-on: ubuntu-latest
container: node:22-bookworm
steps:
- uses: actions/checkout@v7
- run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- run: git describe --tags
- A clone without
actions/checkout, for example in an image with no Node.js, needs it before the clone (nexus #1). - For a single command,
git -c safe.directory="$PWD" statusworks too. The setting is read only from global, system and command-line configuration, never from the repository's own.git/config. safe.directory '*'turns the check off for every repository. It is reasonable in a throwaway container, less so on a self-hosted machine that checks out pull requests from forks.
2. A Docker action, or docker run with the workspace mounted
- A Docker container action gets the workspace at
/github/workspaceand usually runs as root. psalm-github-actions fixed itscomposer installerror inside its image (#72); if an action you use does this, update it. If you maintain one, add the exception in the entrypoint. docker run -v "$PWD":/srcin a step runs as root on a directory owned by the runner's user, and the runner's git settings do not exist in the container (agyloop #352). Run the container as your user with-u "$(id -u):$(id -g)", or add the exception inside it.
3. A self-hosted runner whose steps run as another account
On one Windows runner the checkout belonged to the user who set it up and the steps ran as NETWORK SERVICE, so gh release create failed on C:/actions-runner/_work/… (ocgp-godot-tps-bench #8). Run the runner service as the account that owns its work folder, or add the exception for the job. A container job on a self-hosted runner is case 1 (sast-benchmarks #18).
It can fail without failing the job
When git's error is hidden, the job goes green with a wrong answer. A deploy guard with 2>/dev/null and || reported a commit as missing (CellarNode .github #48), and a drift check in a container job never saw drift (#237). Search the log for "dubious ownership" even when the run passed. CellarNode reproduced it on a laptop with GIT_TEST_ASSUME_DIFFERENT_OWNER=1.
Telling it apart
- "fatal: not a git repository (or any of the parent directories): .git": there is no checkout where the step runs, or
working-directorypoints elsewhere. - "could not read Username for 'https://github.com'": git used the repository and then had no credentials for the remote.
- The check began with Git 2.35.2 in April 2022. A failure that appears after an image or tool update usually means something now runs as another user, not that git changed again.
See failed jobs from IntelliJ IDEA
Pipeline Inbox for GitHub Actions Workflows, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, lists the runs of all your repositories in an IDE tool window, with their jobs and steps, and your current branch's runs are in the status bar. Reading is free; re-running failed jobs, cancelling, running workflows and reviewing deployments are Pro (US$1.50 a month, with a 30-day trial).
GitHub and GitHub Actions are trademarks of GitHub, Inc.; Git is a trademark of Software Freedom Conservancy; Docker is a trademark of Docker, Inc.; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with, sponsored or endorsed by GitHub, Inc., Software Freedom Conservancy, Docker, Inc. or JetBrains.
More: "could not read Username for 'https://github.com'" · "Permission to ... denied to github-actions[bot]" on git push · "No space left on device" · GitHub Actions plugins for IntelliJ IDEA compared · 日本語