This error occurs in Azure DevOps when a build validation policy on a protected branch fails, preventing a push or pull request merge. The fix typically involves ensuring the build pipeline passes, correcting branch policy configuration, or using pull requests instead of direct pushes.
The "TF401028: Build validation failed" error in Azure DevOps indicates that your push or pull request cannot be completed because a required build validation policy has not been satisfied. Branch policies in Azure DevOps can require that changes pass a build pipeline before being merged into a protected branch. When you configure a build validation policy on a branch (such as `main` or `develop`), Azure DevOps queues a build whenever a pull request targets that branch. The PR can only be completed if the build succeeds. If you try to push directly to a protected branch (bypassing pull requests), or if the associated build fails, you'll encounter this TF401028 error. This is a deliberate security and quality gate mechanism. It ensures that only code that has been validated by your CI pipeline makes it into protected branches. The error protects your codebase from broken builds, failing tests, or code that doesn't meet your quality standards. Common scenarios that trigger this error: - **Direct push to a protected branch**: Branch policies require pull requests, but you tried to push directly - **Build pipeline failure**: The validation build failed due to compilation errors, test failures, or other issues - **Unable to queue build**: The pipeline cannot be triggered due to misconfiguration or permissions - **Build expiration**: A previously passing build expired after branch updates
If you're trying to push directly to a protected branch, you need to use a pull request instead:
Create a feature branch and push there:
# Create and switch to a new branch
git checkout -b feature/my-changes
# Push to the feature branch (this will work)
git push -u origin feature/my-changesCreate a pull request:
1. Go to Azure DevOps > Repos > Pull Requests
2. Click "New pull request"
3. Select your feature branch as source, protected branch as target
4. Fill in the title and description
5. Click "Create"
The build validation will trigger automatically. Once it passes, you can complete the PR.
Note: Direct pushes are blocked by design when branch policies are enabled. This is intentional to enforce code review and validation workflows.
When your pull request is open, check why the build is failing:
View build status:
1. Open your pull request in Azure DevOps
2. Look at the "Checks" or "Policies" section
3. Click on the build validation policy to see details
4. Click "View build" to see the full build log
Common build failures:
- Compilation errors: Fix code errors and push to your branch
- Test failures: Review failed tests and fix them
- Linting/code analysis issues: Address code style violations
- Missing dependencies: Update package references
To retry the build:
# Make fixes locally
git add .
git commit -m "Fix build errors"
git pushThe build will automatically re-queue when you push changes to the PR source branch.
If the build cannot even be queued, check these common issues:
1. Pipeline and repository mismatch:
The pipeline must be created from the same repository as the pull request. If you created a pipeline from Repository A and try to use it for PRs in Repository B, it won't work.
2. Pipeline not visible in policy settings:
- Go to Project Settings > Repositories > [Your Repo] > Policies > [Branch]
- Under Build validation, check if your pipeline is selectable
- If not, run the pipeline at least once manually first
3. YAML file missing or invalid:
Ensure your pipeline YAML file exists in both the source and target branches:
# Check if azure-pipelines.yml exists
git ls-files | grep -i pipeline
# Validate YAML syntax (basic check)
cat azure-pipelines.yml4. Permissions issues:
- Go to Project Settings > Pipelines > [Your Pipeline]
- Click "Security"
- Ensure "Build Administrators" and your user have "Queue builds" permission
5. Re-select the pipeline in branch policy:
- Go to Project Settings > Repositories > Policies > [Branch]
- Remove the old build validation policy
- Add a new one and select the correct pipeline
Build validation can expire if the target branch is updated after your PR build completed:
Check expiration settings:
1. Go to Project Settings > Repositories > [Repo] > Policies > [Branch]
2. Click on the build validation policy
3. Review "Build expiration" setting:
- "Immediately when branch updates" - Most strict
- "After N hours if branch updated" - Balanced
- "Never" - Build never expires (least strict)
Update your branch to re-trigger build:
# Fetch latest changes
git fetch origin
# Rebase your branch on the target
git rebase origin/main
# Push (force push if rebased)
git push --force-with-leaseAlternatively, merge the target branch into your feature branch:
git fetch origin
git merge origin/main
git pushThis brings in the latest changes and triggers a new validation build.
In emergency situations, you may need to bypass build validation. This requires special permissions:
Two bypass permissions exist:
- Bypass policies when completing pull requests: Complete PRs even if policies aren't satisfied
- Bypass policies when pushing: Push directly to protected branches
To request bypass:
1. Contact your Azure DevOps Project Administrator
2. They can grant bypass permissions at project, repo, or branch level
3. Go to Project Settings > Repositories > [Repo] > Security
4. Find your user or group
5. Set "Bypass policies when completing pull requests" to Allow
Using bypass when completing PR:
1. Open your pull request
2. Click "Complete"
3. Check "Override branch policies and enable merge"
4. Complete the merge
Warning: Use bypass sparingly. It circumvents quality gates that protect your codebase. Document why bypass was needed.
A specific TF401028 error occurs when multiple clients try to update the same reference simultaneously:
Error message:
TF401028: The reference 'refs/heads/main' has already been updated by another client, so you cannot update it.This happens when:
- Multiple CI/CD pipelines update the same branch
- Terraform or other automation tools conflict
- Parallel PR completions occur
Solutions:
1. Retry the operation:
git fetch origin
git pull --rebase origin main
git push2. For Terraform Azure DevOps provider:
If using azuredevops_git_repository with default_branch:
- Remove initialization.init_type = "Clean" when using parent_repository_id
- Or set default_branch after initial repository creation
3. Implement retry logic in CI/CD:
# Azure Pipelines example with retries
- script: |
for i in 1 2 3; do
git push && break || sleep 5
done
displayName: 'Push with retry'4. Use branch locks for critical operations:
Consider using Azure DevOps branch locks during sensitive operations to prevent concurrent updates.
Misconfigured branch policies are a common cause of build validation failures:
Review branch policies:
1. Go to Project Settings > Repositories
2. Select your repository
3. Go to Policies tab
4. Select the protected branch (e.g., main, develop)
Correct build validation setup:
1. Click "+" next to Build validation
2. Select your pipeline from the dropdown
3. Configure options:
- Trigger: Automatic (recommended) or Manual
- Policy requirement: Required (blocks merge) or Optional (advisory)
- Build expiration: Choose based on your workflow
- Display name: Descriptive name for the check
4. Optionally add path filters to limit which files trigger validation
Path filters example:
# Include only src folder changes
/src/*
# Exclude documentation
!/docs/*Test the configuration:
1. Create a test PR with a small change
2. Verify the build triggers automatically
3. Check that the PR shows the build status
4. Confirm merge is blocked until build passes
Common misconfigurations:
- Wrong pipeline selected
- Pipeline from different repository
- Path filters excluding all changes
- Policy set to "Optional" when "Required" was intended
Understanding Azure DevOps Branch Policies:
Branch policies in Azure DevOps are server-side enforcements that protect important branches. Unlike Git hooks which can be bypassed, branch policies are enforced by the Azure DevOps server and cannot be circumvented without explicit bypass permissions.
Types of branch policies:
- Require a minimum number of reviewers: Ensures code review
- Check for linked work items: Enforces traceability
- Check for comment resolution: All PR comments must be resolved
- Build validation: Requires CI pipeline to pass (this error)
- Require approval from additional services: External validations
Build Validation Pipeline Requirements:
Your validation pipeline must:
1. Exist in the same project as the repository
2. Be triggered by the same repository (for same-repo validation)
3. Have a valid YAML file in both source and target branches
4. Be authorized to run (not waiting for manual approval)
Cross-Repository Build Validation:
You can validate PRs against pipelines in other repositories, but:
- The pipeline must explicitly support this configuration
- Triggers need to be set up correctly
- The build must be able to access the PR source code
YAML Pipeline for PR Validation:
# azure-pipelines.yml
trigger:
- main # CI trigger for main branch
pr:
- main # PR validation trigger
- develop
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '18.x'
- script: npm ci
displayName: 'Install dependencies'
- script: npm run build
displayName: 'Build'
- script: npm test
displayName: 'Run tests'Monitoring Build Validation:
Use Azure DevOps REST API to monitor policy status:
curl -u :$PAT "https://dev.azure.com/{org}/{project}/_apis/policy/evaluations?artifactId={prId}&api-version=7.0"Related Error Codes:
- TF401019: Repository not found or no permissions
- TF401027: Missing Git permissions (GenericContribute)
- TF401028: Build validation failed (this error)
- TF402455: Push to branch not permitted (requires pull request)
Best Practices:
1. Keep validation builds fast: Long builds slow down development
2. Use caching: Cache dependencies to speed up builds
3. Implement partial builds: Only validate affected components
4. Set reasonable expiration: Balance freshness with re-running builds
5. Document bypass procedures: Clear escalation path for emergencies
6. Monitor build success rates: Track and improve flaky tests
Integration with External CI Systems:
If using Jenkins, GitHub Actions, or other CI systems with Azure DevOps:
1. Configure status checks via Azure DevOps REST API
2. Use the Azure DevOps extension for your CI system
3. Set up webhooks to update Azure DevOps on build completion
Azure DevOps displays external build status in the PR if configured correctly.
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