{"record":{"id":"3f12893b4478a51e","repo":"can1357/oh-my-pi","slug":"github-api-request-timed-out","errorCode":null,"errorMessage":"GitHub API request timed out","messagePattern":"GitHub API request timed out","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/utils/tools-manager.ts","lineNumber":182,"sourceCode":"\tif (fs.existsSync(localPath)) {\n\t\treturn localPath;\n\t}\n\n\t// Check system PATH\n\treturn $which(config.binaryName);\n}\n\n// Fetch latest release version from GitHub\nasync function getLatestVersion(repo: string, signal?: AbortSignal): Promise<string> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {\n\t\t\theaders: { \"User-Agent\": USER_AGENT },\n\t\t\tsignal: ptree.combineSignals(signal, TOOL_METADATA_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tif (err instanceof Error && err.name === \"AbortError\") {\n\t\t\tthrow new Error(\"GitHub API request timed out\");\n\t\t}\n\t\tthrow err;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n/** Download a tool asset without handing the streaming Response to Bun.write. */\nexport async function downloadFile(url: string, dest: string, signal?: AbortSignal): Promise<void> {\n\tconst downloadSignal = ptree.combineSignals(signal, TOOL_DOWNLOAD_TIMEOUT_MS);\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/utils/tools-manager.ts#L164-L200","documentation":"getLatestVersion() queries the GitHub releases API to find the latest release tag for a tool's repo. The fetch is wrapped with a combined timeout signal (TOOL_METADATA_TIMEOUT_MS); when the request aborts because that deadline elapsed, the AbortError is translated into this explicit error so callers see a meaningful message instead of a raw DOMException.","triggerScenarios":"Calling version/download for a tool when the HTTPS request to https://api.github.com/repos/<repo>/releases/latest does not complete within TOOL_METADATA_TIMEOUT_MS — the fetch is aborted via the combined AbortSignal and rethrown as this error.","commonSituations":"Slow or flaky network, corporate proxies or VPNs delaying GitHub API responses, GitHub API slowness/outages, or an offline machine with long TCP hangs before failure.","solutions":["Retry the operation once network connectivity is restored — the timeout is per-request, so a simple retry often succeeds.","Check reachability of api.github.com (curl https://api.github.com/rate_limit) to distinguish slowness from a full outage.","Increase TOOL_METADATA_TIMEOUT_MS if you routinely operate on high-latency networks.","Bypass corporate proxy/VPN interference or configure HTTPS_PROXY for the process.","If offline, install the tool manually and rely on the cached installed path instead of the version check."],"exampleFix":"// before: const version = await toolsManager.version(\"sg\") // throws on timeout | // after: wrap in try/catch, on err.message === \"GitHub API request timed out\" use a cached or pinned fallbackVersion, else rethrow","handlingStrategy":"retry","validationCode":"// pre-check connectivity and endpoint latency before calling version() | const probe = await fetch(\"https://api.github.com/rate_limit\", { signal: AbortSignal.timeout(5000) }); if (!probe.ok) throw new Error(\"GitHub API unreachable; skip version check\");","typeGuard":"function isTimeoutError(err: unknown): err is Error { return err instanceof Error && (err.name === \"AbortError\" || err.message === \"GitHub API request timed out\"); }","tryCatchPattern":"try { const version = await toolsManager.version(\"rg\"); } catch (err) { if (isTimeoutError(err)) { await Bun.sleep(1000); /* retry with backoff */ } else throw err; }","preventionTips":["Wrap version checks in a retry with exponential backoff.","Set a sane caller-side AbortSignal so hangs fail fast in your context.","Monitor api.github.com status before batch operations.","Provide a pinned/cached fallback version for offline operation."],"tags":["network","timeout","github-api"],"backgroundTag":"request-timeout","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}