When CI fails on a PR, follow this process to diagnose and fix the issue.
Step 1: Identify the Failure
bash
# List recent workflow runs for the PR gh run list --branch <branch-name> --limit 5
Or use the GitHub MCP Server:
- •
list_workflow_runsto find the failed run. - •
list_workflow_jobsto find the failed job.
Step 2: Get the Logs
bash
# View logs for a specific run gh run view <run-id> --log-failed
Or use the GitHub MCP Server:
- •
get_job_logswithreturn_content: truefor the failed job. - •Use
tail_lines: 100to get the relevant end of the log.
Step 3: Categorize the Failure
| Category | Symptoms | Action |
|---|---|---|
| Build failure | Compilation errors, type errors | Fix the code |
| Test failure | Assertion errors, test timeouts | Fix the test or the code |
| Lint failure | Style violations, warnings-as-errors | Run formatter/linter locally, fix |
| Dependency failure | Package not found, version conflict | Check lockfile, pin versions |
| Infra failure | Network timeout, runner issue | Retry the run |
| PR size check | Diff too large | Split into stacked PRs |
Step 4: Reproduce Locally
bash
# Run the same command that failed in CI, inside the devcontainer devcontainer exec --workspace-folder . <failed-command>
Step 5: Fix and Verify
- •Fix the issue.
- •Run the failing command locally to confirm the fix.
- •Commit with a clear message:
fix(ci): resolve <what was broken>. - •Push and verify CI passes.
Common Pitfalls
- •Flaky tests: If a test passes locally but fails in CI, check for timing dependencies, environment assumptions, or non-deterministic behavior.
- •Different environments: CI may use a different OS, Node version, or Python version. Check the workflow file.
- •Cached state: CI runs from clean state. If it works locally, check for uncommitted files or local-only config.