{"record":{"id":"4be8b3f222d58831","repo":"can1357/oh-my-pi","slug":"repo-full-number-is-a-pull-request-not-an-iss","errorCode":null,"errorMessage":"{repo_full}#{number} is a pull request, not an issue","messagePattern":"(.+?)#(.+?) is a pull request, not an issue","errorType":"exception","errorClass":"ManualTriageError","httpStatus":null,"severity":"error","filePath":"python/robomp/src/manual_triage.py","lineNumber":69,"sourceCode":"def parse_issue_ref(ref: str) -> tuple[str, int]:\n    \"\"\"Parse `owner/repo#NN` or a github issue url into `(\"owner/repo\", NN)`.\"\"\"\n    cleaned = ref.strip()\n    match = _ISSUE_REF.match(cleaned) or _ISSUE_URL.match(cleaned)\n    if match is None:\n        raise InvalidIssueRef(f\"expected owner/repo#NN or https://github.com/owner/repo/issues/NN, got {ref!r}\")\n    return f\"{match.group('owner')}/{match.group('repo')}\", int(match.group(\"number\"))\n\n\ndef manual_delivery_id(repo_full: str, number: int) -> str:\n    \"\"\"Stable delivery id for manually-triggered triage. Re-runs reuse it.\"\"\"\n    return f\"manual-{repo_full.replace('/', '__')}-{number}\"\n\n\nasync def build_issues_opened_payload(github: GitHubBackend, repo_full: str, number: int) -> dict[str, Any]:\n    \"\"\"Fetch the issue + repo metadata and synthesize an `issues.opened` payload.\"\"\"\n    issue = await github.get_issue(repo_full, number)\n    if issue.is_pull_request:\n        raise ManualTriageError(f\"{repo_full}#{number} is a pull request, not an issue\")\n    repo = await github.get_repo(repo_full)\n    return {\n        \"action\": \"opened\",\n        \"issue\": {\n            \"number\": issue.number,\n            \"title\": issue.title,\n            \"body\": issue.body,\n            \"state\": issue.state,\n            \"user\": {\"login\": issue.author},\n            \"labels\": [{\"name\": lbl} for lbl in issue.labels],\n        },\n        \"repository\": {\n            \"full_name\": repo.full_name,\n            \"default_branch\": repo.default_branch,\n            \"clone_url\": repo.clone_url,\n            \"private\": repo.private,\n        },\n    }","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/manual_triage.py#L51-L87","documentation":"ManualTriageError raised by build_issues_opened_payload when the fetched GitHub item has the is_pull_request flag set, meaning manual triage was pointed at a PR instead of a real issue. It synthesizes `issues.opened` payloads only for issues.","triggerScenarios":"enqueue_manual_triage(repo, number) where number resolves to a PR; GitHub's issues API returns PRs under the /issues endpoint so numbers overlap.","commonSituations":"Copy-pasting a PR number/URL into manual triage, off-by-one confusion since issue and PR numbers share one sequence per repo.","solutions":["Use a genuine issue number, not a PR number","Check the item first (e.g. via the GitHub web UI) — URLs ending in /pull/NN are PRs","If PR triage is needed, use the PR-specific flow instead of manual issue triage"],"exampleFix":"// before\nawait enqueue_manual_triage(github, db, \"org/repo\", 42)  # 42 is a PR\n// after: pick the issue number\nawait enqueue_manual_triage(github, db, \"org/repo\", 43)  # real issue","handlingStrategy":"validation","validationCode":"issue = await github.get_issue(repo_full, number)\nif issue.is_pull_request:\n    raise ValueError(f\"{repo_full}#{number} is a PR, not an issue\")","typeGuard":"def is_real_issue(issue) -> bool:\n    return not issue.is_pull_request","tryCatchPattern":"try:\n    delivery = await enqueue_manual_triage(github, db, repo_full, number)\nexcept ManualTriageError as e:\n    log.info(\"not an issue: %s\", e)\n    return None","preventionTips":["Confirm the number is an issue (URL contains /issues/ not /pull/)","Remember issue and PR numbers share one sequence per repo","Validate the fetched item's is_pull_request flag before enqueueing"],"tags":["github","validation","pull-request"],"backgroundTag":"pull-request-vs-issue","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}