{"record":{"id":"70e9bed6697d6a1b","repo":"sigoden/aichat","slug":"not-found-branch-or-tag","errorCode":null,"errorMessage":"Not found branch or tag","messagePattern":"Not found branch or tag","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/utils/request.rs","lineNumber":333,"sourceCode":"    let repo = path_segs[2];\n    let branch = path_segs[4];\n    let root_path = path_segs[5..].join(\"/\");\n\n    let url = format!(\"https://api.github.com/repos/{owner}/{repo}/git/ref/heads/{branch}\");\n\n    let res_body: Value = client\n        .get(&url)\n        .header(\"User-Agent\", USER_AGENT)\n        .header(\"Accept\", \"application/vnd.github+json\")\n        .header(\"X-GitHub-Api-Version\", \"2022-11-28\")\n        .send()\n        .await?\n        .json()\n        .await?;\n\n    let sha = res_body[\"object\"][\"sha\"]\n        .as_str()\n        .ok_or_else(|| anyhow!(\"Not found branch or tag\"))?;\n\n    let url = format!(\"https://api.github.com/repos/{owner}/{repo}/git/trees/{sha}?recursive=true\");\n\n    let res_body: Value = client\n        .get(&url)\n        .header(\"User-Agent\", USER_AGENT)\n        .header(\"Accept\", \"application/vnd.github+json\")\n        .header(\"X-GitHub-Api-Version\", \"2022-11-28\")\n        .send()\n        .await?\n        .json()\n        .await?;\n    let tree = res_body[\"tree\"]\n        .as_array()\n        .ok_or_else(|| anyhow!(\"Invalid github repo tree\"))?;\n    let paths = tree\n        .iter()\n        .flat_map(|v| {","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/utils/request.rs#L315-L351","documentation":"`crawl_gh_tree` first queries the GitHub API for a ref (`/repos/{owner}/{repo}` ref/branches/tags endpoint) to obtain the commit SHA. When the response JSON lacks `object.sha` — typically because the branch or tag does not exist or the ref name is wrong — it returns `anyhow!(\"Not found branch or tag\")`. The request itself succeeded (HTTP-level errors are handled earlier), but the payload has no SHA.","triggerScenarios":"Crawling a GitHub repo URL that specifies a branch or tag name which does not exist upstream, is misspelled, or was deleted; also when the API returns an error object instead of a ref object.","commonSituations":"Default branch renamed from `master` to `main` (or vice versa) in the URL; pinning a deleted tag/version; repo moved or renamed so the ref endpoint returns an error body without `object.sha`.","solutions":["Verify the branch/tag name in the URL exists in the repo (git ls-remote --heads/--tags origin).","Use the default branch instead of a hardcoded one, or resolve `HEAD` first.","Check the GitHub API response for an error message (rate limit, 404) — a 403/404 body also lacks object.sha.","Ensure authentication if the repo or ref is private; unauthenticated requests can 404 on private refs."],"exampleFix":"// before\nlet url = \"https://raw.githubusercontent.com/owner/repo/master/docs\"; // branch deleted\n// after\nlet url = \"https://raw.githubusercontent.com/owner/repo/main/docs\"; // verify with git ls-remote --heads","handlingStrategy":"validation","validationCode":"async fn ref_exists(owner: &str, repo: &str, r: &str, token: Option<&str>) -> bool {\n    let url = format!(\"https://api.github.com/repos/{owner}/{repo}/git/ref/heads/{r}\");\n    let mut req = reqwest::Client::new().get(&url).header(\"User-Agent\", \"check\");\n    if let Some(t) = token { req = req.bearer_auth(t); }\n    req.send().await.map(|v| v.status().is_success()).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match crawl_gh_tree(owner, repo, r, client).await {\n    Err(e) if e.to_string() == \"Not found branch or tag\" => {\n        eprintln!(\"Branch/tag '{r}' not found; falling back to default branch\");\n    }\n    other => other?,\n}","preventionTips":["Verify branch/tag names with `git ls-remote` before crawling.","Resolve the repo's default branch instead of hardcoding 'master'/'main'.","Authenticate with a GitHub token to avoid 404s on private refs and rate limits.","Handle the `message` field in GitHub error bodies explicitly."],"tags":["github","api","git-ref","crawler"],"backgroundTag":"resource-not-found","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}