Troubleshoot a check¶
Use this guide when Extra CODEOWNERS / approval is missing, pending, or
failed on a pull request. Start with the check's own summary. It is written for
the pull-request author and repository maintainer; service operators have a
separate recovery runbook.
Don't publish a replacement success or weaken repository rules to clear the symptom.
Confirm the current head¶
Read the pull request's current head commit:
gh pr view NUMBER --repo OWNER/REPOSITORY --json headRefOid --jq .headRefOid
Replace NUMBER, OWNER, and REPOSITORY. Compare that SHA with the commit
shown beside the Extra CODEOWNERS check. A success on an older commit does not
apply to the current head.
List the checks GitHub associates with the pull request:
gh pr checks NUMBER --repo OWNER/REPOSITORY
The expected check name is Extra CODEOWNERS / approval unless the operator
changed it. A repository rule should also select the Extra CODEOWNERS App as
the expected source; another workflow can reuse the same text.
If the check is missing¶
Extra CODEOWNERS stays silent when all three of these facts are true:
- repository policy is absent at the configured path
- the repository has no Extra CODEOWNERS check for the current head
- organization policy alone is the only configuration.
Read repository policy from the pull request's base commit, not from the
proposed change. The default path is .github/extra-codeowners.toml. It must
contain:
schema_version = 1
enabled = true
If policy exists and the check is still missing, ask a repository administrator
to confirm that the App can access both the target repository and the
organization policy repository. The latter is the organization's .github
repository by default.
The organization policy repository itself never receives an Extra CODEOWNERS check in schema version 1. It must keep native human code-owner enforcement.
If the check failed¶
Open Details beside the check. Match the summary to the next action.
| Summary or condition | What to do |
|---|---|
| A human owner is unresolved | Ask one of the listed users, or a member of a listed team, to approve the current head. |
| An App approval is missing | Confirm that the enrolled App approved the current head. A comment is not an approval. |
| An App approval is ineligible | Check the delegated path, owner, required labels, forbidden labels, and enrolled App identity. |
| The approval names an older commit | Pushes make earlier approval evidence stale. Ask the owner or App to approve the new head. |
| A path is non-delegable | An App cannot substitute on that path. Ask an eligible human CODEOWNER to approve. |
| Policy is disabled or missing after enrollment | Restore valid enabled policy, or follow the safe disablement order below. |
| Policy or CODEOWNERS is invalid | Validate both policy files and inspect GitHub's CODEOWNERS errors. |
| Several open pull requests share the head | Give each pull request a distinct commit, then wait for reevaluation. |
| The changed-file limit was reached | Split or reduce the pull request. Extra CODEOWNERS will not authorize a truncated file list. |
Labels change whether an App delegation is eligible. Adding a label never counts as approval. An eligible human approval can still satisfy an owner set when an App delegation's label conditions do not match.
An approving App already has permission to change pull-request labels, so label conditions are not an independent defense against that App being compromised. Investigate the App and rotate its credentials; do not try to contain the incident with labels.
Validate policy¶
From a reviewed Extra CODEOWNERS checkout with dependencies installed, run:
mise exec -- uv run python -m extra_codeowners validate-policy \
--repository /path/to/repository-policy.toml \
--organization /path/to/organization-policy.toml
Success prints:
Policy files are valid.
The command checks TOML, field constraints, path patterns, App aliases, and cross-file enrollment. Live evaluation also checks repository access, current labels, App identity, CODEOWNERS, and reviews.
Check GitHub's view of the standard file separately:
BASE_SHA="$(
gh pr view NUMBER --repo OWNER/REPOSITORY \
--json baseRefOid --jq .baseRefOid
)"
gh api --method GET repos/OWNER/REPOSITORY/codeowners/errors \
-f ref="$BASE_SHA" \
--jq '.errors'
Replace the pull-request number and repository. An error-free file at that
exact base commit prints [].
If the check stays pending¶
An in_progress result blocks merging while Extra CODEOWNERS invalidates stale
evidence, reevaluates the pull request, fans out an authority change, or waits
for GitHub or the database to recover.
Wait through the deployment's normal evaluation interval. If the result lasts longer than that interval, give the operator:
- repository and pull-request number
- exact head SHA
- check name and current status
- sanitized check summary
- GitHub webhook delivery ID, if an administrator can see it
- the time of the last relevant push, review, or label change in UTC.
Do not include a private key, webhook secret, installation token, authorization header, complete webhook payload, private repository contents, or a database URL.
The operator should continue with Investigate a missing or stale check. A long-lived pending check needs service recovery, not a manufactured result.
Test a correction¶
After changing policy, labels, or review state, confirm all of these facts on the exact current head:
- The expected Extra CODEOWNERS App published the check.
- The check summary names the paths and owners you expected.
- Every approval shown as satisfying policy belongs to the current head.
- The repository's ordinary approval count and other required checks still pass independently.
Run a negative case before expanding App authority. Remove a required label, dismiss the App review, or change an undelegated path. The check must stop succeeding. If it does not, restore native code-owner enforcement and stop the rollout.
Disable the check without leaving a gap¶
If a repository must stop using Extra CODEOWNERS:
- Restore GitHub's native Require review from Code Owners rule.
- Wait until GitHub shows that rule as active.
- Remove the required Extra CODEOWNERS check.
- Disable or remove repository policy.
- Remove App access only after the native rule is working.
The order matters. Once the App loses repository access, it may be unable to replace an earlier success with a blocking result.