zed-industries/zed · error · RuntimeError

project #{project_number} not found

Error message

project #{project_number} not found

What it means

fetch_project_id queries organization(login: REPO_OWNER).projectV2(number: project_number){ id } and GitHub answers with null — not a body error — when the project does not exist under that org or the token cannot see it; the script turns that null into this RuntimeError. Permission failure and wrong number are indistinguishable from here.

Source

Thrown at script/github-triage-queue-board.py:132

        for item in data["items"]:
            issues[item["node_id"]] = item["number"]
        if len(data["items"]) < 100 or page >= 10:
            return issues
        page += 1


def fetch_project_id(project_number):
    data = github_graphql(
        """
        query($owner: String!, $number: Int!) {
          organization(login: $owner) { projectV2(number: $number) { id } }
        }
        """,
        {"owner": REPO_OWNER, "number": project_number},
    )
    project = data["organization"]["projectV2"]
    if not project:
        raise RuntimeError(f"project #{project_number} not found")
    return project["id"]


def project_items(project_id):
    # Yields (item_id, content_id, number) for each issue on the project.
    # content_id is the issue's global node id, which is the same value the REST
    # search API returns as node_id, so it can be compared directly against the
    # keys of eligible_issues().
    cursor = None
    while True:
        data = github_graphql(
            """
            query($project: ID!, $cursor: String) {
              node(id: $project) {
                ... on ProjectV2 {
                  items(first: 100, after: $cursor) {
                    pageInfo { hasNextPage endCursor }
                    nodes { id content { ... on Issue { id number } } }

View on GitHub (pinned to bc538def45)

Solutions

  1. Verify the project number in the board URL and that it is an org project
  2. Check token scopes/fine-grained permissions for project read on that org
  3. Switch to user(login:){ projectV2 } if the project is user-owned
  4. Print REPO_OWNER/PROJECT_NUMBER at startup to catch env mistakes

Example fix

// before
project = data["organization"]["projectV2"]
if not project:
    raise RuntimeError(f"project #{project_number} not found")

// after
project = data["organization"]["projectV2"]
if not project:
    raise RuntimeError(
        f"project #{project_number} not found under {REPO_OWNER}; "
        "check PROJECT_NUMBER, REPO_OWNER, and token project scopes"
    )
Defensive patterns

Strategy: validation

Validate before calling

def project_number_is_plausible(number: int) -> bool:
    return isinstance(number, int) and number > 0

Type guard

def projectv2_visible(data: dict) -> bool:
    org = data.get("organization") or {}
    return bool(org.get("projectV2"))

Try / catch

try:
    project_id = fetch_project_id(project_number)
except RuntimeError as exc:
    if "not found" in str(exc):
        raise SystemExit("Verify PROJECT_NUMBER, REPO_OWNER, and the token's read:project scope")
    raise

Prevention

When it happens

Trigger: PROJECT_NUMBER wrong or referring to a user-level project; token missing read:project scope; project private to another org; REPO_OWNER env wrong so the org lookup yields null projectV2.

Common situations: Board recreated with a new number; rotated token without project scope; workflow targeting the wrong org; fine-grained PAT without the org's projects selected.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/2906bd818f0419c9. Report an issue: GitHub.