jamiepine/voicebox · info · Error
Failed to fetch stars
Error message
Failed to fetch stars
What it means
Thrown in the Navbar useEffect when /api/stars returns non-2xx; caught and console.erroled, leaving starCount null so the badge is hidden. /api/stars proxies getStarCount() which fetches api.github.com/repos/<repo> for stargazers_count with a 10-minute revalidate.
Source
Thrown at landing/src/components/Navbar.tsx:22
import Image from 'next/image';
import { useEffect, useState } from 'react';
import { DONATE_URL, GITHUB_REPO, TOKEN_TICKER } from '@/lib/constants';
function formatStarCount(count: number): string {
if (count >= 1000) {
const k = count / 1000;
return k % 1 === 0 ? `${k}k` : `${k.toFixed(1)}k`;
}
return count.toString();
}
export function Navbar() {
const [starCount, setStarCount] = useState<number | null>(null);
useEffect(() => {
fetch('/api/stars')
.then((res) => {
if (!res.ok) throw new Error('Failed to fetch stars');
return res.json();
})
.then((data) => {
if (typeof data.count === 'number') setStarCount(data.count);
})
.catch((error) => {
console.error('Failed to fetch star count:', error);
});
}, []);
return (
<nav className="fixed inset-x-0 top-0 z-50 border-b border-border/50 bg-background/80 backdrop-blur-xl">
<div className="mx-auto flex max-w-7xl items-center justify-between px-6 py-3 sm:grid sm:grid-cols-[1fr_auto_1fr] sm:gap-x-6">
{/* Logo + wordmark */}
<a href="/" className="flex items-center gap-2.5 justify-self-start">
<Image
src="/voicebox-logo-app.webp"
alt="Voicebox"View on GitHub (pinned to 51f49dea19)
Solutions
- Add a server-side GitHub token to the getStarCount() fetch to raise the rate limit.
- Increase the revalidate window (currently 600s) and ensure the Navbar relies on cached data.
- Hide the star badge gracefully when starCount is null (already the behavior).
- Verify GITHUB_REPO in releases.ts is correct and public.
Example fix
// before
if (!res.ok) throw new Error('Failed to fetch stars');
// after
if (!res.ok) { console.warn('stars status', res.status); return; } Defensive patterns
Strategy: fallback
Type guard
function isStarPayload(v: unknown): v is { count: number } {
return typeof v === 'object' && v !== null && typeof (v as { count?: unknown }).count === 'number';
} Try / catch
try {
const res = await fetch('/api/stars');
if (!res.ok) throw new Error('Failed to fetch stars');
const data = await res.json();
if (typeof data.count === 'number') setStarCount(data.count);
} catch (error) {
console.error('Failed to fetch star count:', error);
// starCount stays null; badge hidden
} Prevention
- Hide the star badge when starCount is null.
- Add a server-side GitHub token; the Navbar mounts on every route and exhausts the 60/hr cap fast.
- Increase the 600s revalidate and lean on cached data.
When it happens
Trigger: GET /api/stars returns 500 because getStarCount() threw (GitHub 403/429 rate limit, repo not found, network). Every page rendering the Navbar triggers the fetch, multiplying rate-limit pressure.
Common situations: Unauthenticated GitHub rate limit (60/hr) exhausted because the Navbar mounts on every landing route. GITHUB_REPO pointing at a renamed/private repo. Deploy IP blocked by GitHub abuse detection.
Related errors
- Failed to fetch releases
- releases ${r.status}
- Failed to fetch releases
- Jupiter HTTP ${res.status}
- pump.fun swap-api HTTP ${res.status}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/3427a597a15c0eee.
Report an issue: GitHub.