bedda.tech logobedda.tech
← Back to blog

Vercel Silent Deploy Failures: Debug via API

Matthew J. Whitney
9 min read
devopsinfrastructurecloud computingoutages

Here's the deal: if your Vercel auto-deploy not triggering problem has you staring at a green CI pipeline while your production branch silently rots, the dashboard is not going to tell you why. I learned this the hard way after a client came to me convinced their GitHub Actions setup was flaky. It wasn't. The problem was 231 days old, completely invisible in the UI, and traced back to a stale gitCredentialId that predated a GitHub App reinstall nobody remembered doing.

This post is about how I found it, what the API told me that the dashboard never would, and why you should add this diagnostic pattern to your runbook today.

The Cloud Computing Trap: Trusting the Dashboard

The Vercel dashboard is good at showing you what's happening. It's bad at showing you what's not happening. When auto-deploys stop firing, the UI gives you nothing. No error state. No failed webhook log front-and-center. Just silence. The project looks healthy. The last deployment shows green. Everything appears fine.

This is the trap. Engineers see a healthy-looking dashboard and immediately blame the thing they changed most recently: CI configuration, GitHub Actions workflows, branch protection rules. They spend hours in the wrong place.

Here's what most guides miss: Vercel's deployment system has two distinct layers. There's the build and deploy layer, which is what the dashboard surfaces well. Then there's the git integration layer, which handles webhook ingestion and credential resolution. When the git integration layer breaks, it fails silently from the UI's perspective. The deployment never gets created, so there's nothing to show as failed. The project just... stops receiving pushes.

The only way to see this clearly is through the Vercel REST API.

Infrastructure Forensics: What the API Actually Exposes

The deployments list endpoint is your first stop:

curl -H "Authorization: Bearer $VERCEL_TOKEN" \
  "https://api.vercel.com/v6/deployments?projectId=YOUR_PROJECT_ID&limit=20&teamId=YOUR_TEAM_ID"

What you're looking for is the meta object on each deployment and specifically the githubCommitRef, githubCommitSha, and source fields. In a healthy project with working auto-deploys, recent deployments will show "source": "git" and have populated commit metadata.

In the broken project I was diagnosing, the last deployment with "source": "git" had a createdAt timestamp that was 231 days old. Every deployment after that was "source": "cli" or manual. The auto-deploy had been dead for over seven months and nobody caught it because the team was doing manual deploys via the CLI as part of their release process. They assumed the auto-deploy was just redundant. It wasn't. It was supposed to be handling preview deployments on feature branches.

The next step was pulling the project configuration:

curl -H "Authorization: Bearer $VERCEL_TOKEN" \
  "https://api.vercel.com/v9/projects/YOUR_PROJECT_ID?teamId=YOUR_TEAM_ID"

Buried in the response under link is the git integration object. It contains the gitCredentialId field. Cross-reference that ID against the actual GitHub App installation, and you'll find whether the credential still maps to a valid, active installation.

In this case, it didn't. The team had uninstalled and reinstalled the Vercel GitHub App roughly eight months prior, likely to resolve an unrelated permissions issue. The reinstall generated a new credential internally. The project's gitCredentialId was never updated to point at the new one. Vercel's webhook handler was receiving pushes, failing to authenticate them against a dead credential, and dropping them with no visible error.

DevOps Blind Spots: Why This Stays Hidden

This category of failure is particularly nasty for a few reasons.

First, the webhook delivery side often looks fine. If you go to your GitHub repository settings and check the Vercel webhook, you'll see recent deliveries with 200 responses. Vercel's webhook receiver accepts the payload. The failure happens downstream, during credential resolution, after the 200 has already been returned to GitHub. So the webhook log, which is where most engineers look first, shows everything as healthy.

Second, Vercel doesn't surface gitCredentialId mismatches as project-level errors. There's no alert, no dashboard warning, no email. The Vercel status page shows nothing because from Vercel's infrastructure perspective, nothing is broken. The system is working exactly as designed. It received a webhook, tried to resolve credentials, failed, and moved on. That's not an outage by any metric Vercel tracks.

Third, teams that have any manual deploy path in their workflow (CLI deploys, GitHub Actions calling the Vercel CLI directly) will mask the problem completely. Production keeps getting updated. The silent failure only affects the git-triggered auto-deploy path.

This connects to something broader happening in the industry right now. As Stack Overflow question volume has dropped 99% from its 2014 peak and developers increasingly rely on AI tools and vendor dashboards for debugging, the institutional knowledge around low-level API forensics is getting thinner. The engineers who know to go off-dashboard when the dashboard looks healthy are becoming rarer. That's a real problem when the silent failures are the dangerous ones.

The gitCredentialId: What It Is and Why It Goes Stale

When you install the Vercel GitHub App on your GitHub organization, Vercel creates an internal credential record that stores the OAuth token and installation ID needed to interact with your repositories. That credential gets a unique ID. When you connect a Vercel project to a GitHub repo, the project stores a reference to that credential ID.

If you ever uninstall and reinstall the GitHub App, revoke and reauthorize the OAuth connection, or in some cases transfer the Vercel team to a different GitHub organization, Vercel creates a new credential record with a new ID. Existing projects that were connected under the old credential don't automatically update. They keep the stale ID.

This is documented behavior in the sense that Vercel's GitHub App integration documentation explains the connection model, but the failure mode of stale credentials is not explicitly called out. You're expected to reconnect projects after certain authentication changes. The problem is that nothing tells you to do this, and nothing tells you when you've failed to do it.

The fix, once you've identified it, is straightforward: go to the project settings in the Vercel dashboard, disconnect the Git repository under the "Git" tab, and reconnect it. This generates a fresh association using the current active credential. Auto-deploys will resume on the next push.

But you have to know to look for it first.

The Diagnostic Runbook

When Vercel auto-deploy not triggering is your problem, here's the sequence I'd run through, in order:

Step 1. Pull the last 20 deployments via API and check the source field on each. If you see a hard cutoff where "source": "git" stops appearing at a specific date, you have a git integration failure, not a CI failure. Note the exact date it stopped.

Step 2. Check your GitHub repository's webhook delivery log for the Vercel webhook around that date. Look for any delivery that returned a non-200, or any gap in deliveries that correlates with the cutoff you found in step 1.

Step 3. Pull the project config via API and extract the gitCredentialId from the link object. If you have Vercel team admin access, check whether that credential ID corresponds to an active GitHub App installation. If you don't have that access, proceed to step 4 anyway.

Step 4. Check the date of any GitHub App reinstalls, OAuth reauthorizations, or team transfers in your audit logs. If any of those events predate or closely correlate with the cutoff from step 1, you have your root cause.

Step 5. Reconnect the repository in project settings. Push a test commit. Verify the new deployment appears with "source": "git" in the API response.

This whole process takes about 20 minutes once you know what you're looking for. Without the API, you could spend days.

Outages You Don't Know About Are the Worst Kind

The 231-day failure I diagnosed wasn't causing visible production issues. But it was causing real business problems. Preview deployments on feature branches weren't happening, so QA was reviewing code from screenshots and staging environments instead of live preview URLs. The team had quietly adapted their workflow around the broken behavior without realizing the workflow was broken. That kind of adaptation is how technical debt accumulates without anyone making a conscious decision to take it on.

If you're running Vercel at any meaningful scale, add a monitoring check that queries the deployments API on a schedule and alerts if the most recent deployment with "source": "git" is older than your expected deploy frequency. This is not a Vercel-provided feature. You have to build it yourself. But it's maybe 30 lines of code and a cron job, and it would have caught this failure within a day instead of 231.

The Vercel deployments API documentation has everything you need to build that check. The source field is returned in the default response shape. You don't need any special scopes beyond standard deployment read access.

The Concrete Recommendation

Stop treating the Vercel dashboard as the source of truth for deployment health. It's a good UI for managing deployments that exist. It's useless for detecting deployments that should exist but don't.

Build API-level monitoring for your Vercel projects. At minimum, track the timestamp of the last git-sourced deployment per project and alert when it exceeds your expected cadence. If you're on a team that does frequent pushes, that threshold might be 24 hours. If you deploy weekly, maybe 10 days. The exact number matters less than having the check at all.

When Vercel auto-deploy not triggering is the complaint, go to the API first. Check the source fields. Find the cutoff date. Then work backward through GitHub App history to find the credential event that caused it.

The dashboard is for shipping. The API is for debugging. Use both accordingly.

Have Questions or Need Help?

Our team is ready to assist you with your project needs.

Contact Us