This error occurs when a server-side Git hook (pre-receive, update, or post-receive) rejects your push operation, preventing reference updates on the remote repository.
Git server-side hooks are scripts that run on the remote repository during push operations to enforce repository policies and quality standards. When you see "hook declined to update refs," it means one of these server-side hooks has rejected your push because it violated a rule or check configured by the repository administrators. Unlike client-side hooks that run on your local machine, server-side hooks execute on the remote Git server and have the authority to accept or reject pushes. The pre-receive and update hooks can prevent commits from being accepted, while post-receive hooks run after the push is complete but can still cause failures if they encounter errors. This is a critical security and quality control mechanism used by platforms like GitHub, GitLab, Bitbucket, and self-hosted Git servers to maintain repository standards, prevent accidental or malicious changes, and enforce organizational policies.
The hook output usually contains specific information about why the push was rejected. Look for custom messages in the error output:
git push origin main
# Read all output between "remote:" linesThe hook script should explain what rule was violated. Common messages include:
- "Commit message must reference JIRA ticket"
- "File size exceeds 100MB limit"
- "Direct pushes to main are not allowed"
- "Tests must pass before pushing"
If pushing to a protected branch, verify the protection rules:
GitHub:
# View protection rules in repository Settings > Branches
# Or use GitHub CLI
gh api repos/{owner}/{repo}/branches/{branch}/protectionGitLab:
# Settings > Repository > Protected Branches
# Check who can push and mergeBitbucket:
# Repository Settings > Branch PermissionsYou may need to:
- Create a pull request instead of pushing directly
- Request maintainer or admin role
- Use a different target branch
Many hooks enforce commit message conventions. Check and fix your commits:
# View recent commit messages
git log -3 --oneline
# Amend the most recent commit message
git commit --amend -m "feat: add user authentication (PROJ-123)"
# Interactive rebase to fix multiple commits
git rebase -i HEAD~3
# Change "pick" to "reword" for commits to fixCommon conventions:
- Conventional Commits: type(scope): description
- JIRA/ticket references required: [PROJ-123] description
- Minimum length requirements
- Signed-off-by line: git commit -s
Hooks often reject pushes containing files that exceed size limits:
# Find large files in your recent commits
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '/^blob/ {print substr($0,6)}' | \
sort -k2 -n | \
tail -20
# Check specific commit
git show --stat HEAD
# Remove large file from history
git filter-branch --tree-filter 'rm -f path/to/large/file' HEAD
# Or use git-filter-repo (recommended)
git filter-repo --path path/to/large/file --invert-pathsIf large files are necessary, consider using Git LFS:
git lfs install
git lfs track "*.psd"
git add .gitattributesSome hooks validate that commit authors match organizational requirements:
# Check your current git identity
git config user.name
git config user.email
# Update to match requirements (e.g., company email)
git config user.email "[email protected]"
git config user.name "Your Name"
# Amend author of last commit
git commit --amend --author="Your Name <[email protected]>" --no-edit
# Fix author for multiple commits
git rebase -i HEAD~3
# Mark commits with "edit", then for each:
git commit --amend --author="Your Name <[email protected]>" --no-edit
git rebase --continueIf direct pushes are not allowed, create a pull request instead:
# Create and push to a feature branch
git checkout -b feature/my-changes
git push -u origin feature/my-changes
# Create PR via GitHub CLI
gh pr create --title "Add feature" --body "Description"
# Or via GitLab CLI
glab mr create --title "Add feature"
# Or push to a different branch
git push origin HEAD:feature/my-changesThis allows hooks to validate your changes and team members to review before merging.
If you cannot determine the cause or resolve the issue:
# Get repository administrators
# GitHub:
gh api repos/{owner}/{repo}/collaborators --jq '.[] | select(.permissions.admin==true) | .login'
# Check repository settings/documentation
cat CONTRIBUTING.md
cat .github/PULL_REQUEST_TEMPLATE.mdProvide them with:
- The complete error output
- Your commit SHA and branch name
- What you are trying to accomplish
- Any custom error messages from the hook
Administrators can:
- Explain specific hook requirements
- Temporarily bypass hooks if necessary
- Grant you elevated permissions
- Fix broken or misconfigured hooks
Server-side Git hooks are stored in the .git/hooks directory on the remote repository and are not cloned with the repository for security reasons. Common server-side hooks include:
pre-receive: Runs once per push operation before any refs are updated. Receives all refs being pushed and can reject the entire push if it exits with non-zero status. This is the most commonly used hook for enforcing repository-wide policies.
update: Runs once per branch being updated. Unlike pre-receive, it can accept some branches while rejecting others in the same push. Useful for branch-specific rules.
post-receive: Runs after all refs are updated successfully. Cannot reject the push but can perform follow-up actions like deployment, notifications, or CI triggering. Failures in post-receive hooks will show errors but won't rollback the push.
When debugging hook failures, remember that hook scripts can be written in any language (bash, Python, Ruby, etc.) and may depend on external tools or services. Timeout issues can occur if hooks perform long-running operations like running full test suites or contacting external APIs. Some platforms (GitLab, GitHub Enterprise) have hook timeout limits (typically 10-60 seconds).
For self-hosted Git servers, hooks must be executable (chmod +x) and have proper shebangs. Hook output goes to the client, so hooks should provide clear, actionable error messages. Security note: Never bypass hook checks by force-pushing unless you fully understand the implications and have proper authorization.
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git