Repository navigation
Troubleshooting
Problems you are likely to meet with this code, what causes them, and how to fix them. The quoted messages are the ones the code prints. The FAQ is at the bottom.
Cause: your Node.js is older than the pinned packages need. @sparticuz/chromium 153.0.0 needs Node ^22.17.0 || >=24.0.0, and puppeteer-core 25.11.0 needs >=22.12.0.
Fix: install Node.js 22.17+ or 24+ (see Installation), delete node_modules, and run npm install again.
Cause: the script runs next lint, and Next.js 16 removed that command. The repository has no ESLint configuration file either.
Fix: use Biome, which is already a dev dependency and configured in biome.json:
npx @biomejs/biome lint .To lint and check formatting together:
npx @biomejs/biome check .Cause: the script runs next export, which current Next.js versions no longer provide, and the site needs a server anyway.
Fix: use npm run build and npm start, or deploy to Vercel. See Deployment.
Cause: the fonts are loaded with next/font/google (Geist and Geist Mono), which downloads them during the build.
Fix: build on a machine with internet access. To avoid the download entirely, switch the fonts in src/resources/once-ui.config.ts to next/font/local with font files you add to the project.
Cause: RouteGuard only shows pages that are listed in routes in src/resources/once-ui.config.ts with the value true (plus anything under /work and /blog when those are on). This also applies to new pages you create yourself.
Fix: add the path to routes:
const routes: RoutesConfig = {
// ...
"/contact": true,
};To show it in the header too, add a button for it in src/components/Header.tsx, following the existing ones.
Cause: the repository has no blog pages (src/app/blog/ does not exist). The setting only turns on the header button, the "Latest from the blog" block on Home and the sitemap entry.
Fix: set /blog back to false, or build the blog pages yourself.
Cause: that token is not known to src/lib/live-stats.ts. Unknown tokens are left as they are.
Fix: replace the token with plain text, or add the project and key to SOURCES and FALLBACK in live-stats.ts. See Live numbers.
Cause: the stats page could not be fetched (no internet during the build, a timeout, or an HTTP error).
Fix: nothing breaks: the values in FALLBACK are used. If you do not use the author's numbers, remove the tokens from your text so the site no longer depends on codeshare.me.
Cause: the GitHub API returned an error or nothing at all. GitHub limits how often unauthenticated requests can be made, and builds on shared machines hit that limit more easily. The message is also shown when every repository you have is pinned, or github.username has no public repositories.
Fix: check github.username in site-data.tsx, then wait. The data is cached for one hour, so the page recovers on its own once GitHub answers again.
Cause: pins are read from your public GitHub profile page. If that read fails, the site falls back to github.highlight. Pinned repositories owned by an organisation are left out, because they are not in your own repository list.
Fix: pin the repositories you want on your GitHub profile, and keep github.highlight up to date as a fallback.
The route could not capture the project's website. During npm run dev and npm run build it then shows the first image in the project's images instead, so the page still works.
| Reason in the log | What it means | Fix |
|---|---|---|
| An error about launching the browser | Chromium could not start (common on Windows and macOS, where the bundled Linux build does not run) | Set CHROMIUM_PATH to an installed Chrome or Chromium, or ignore it locally |
HTTP 4xx / HTTP 5xx / HTTP no response
|
The site returned an error | Check link / screenshotUrl
|
landed on a bot check or consent page ("...") |
The site showed "Just a moment", "Verify you are human", a consent wall and so on | Use screenshotUrl for a page without the check, or screenshot: false
|
| A navigation timeout | The page took more than 25 seconds to load | Use a lighter page in screenshotUrl, or screenshot: false
|
Cause: the project has no entry in images. Without one there is no cover and no live screenshot, because the screenshot needs a fallback.
Fix: add at least one image path under images in the project's front matter.
Cause: gallery in site-data.tsx lists a /screenshots/<slug> for a project you deleted, or a file that is not in public/.
Fix: remove or correct that entry.
Cause: you used an image from another website. next.config.mjs only allows www.google.com.
Fix: add the host to images.remotePatterns:
images: {
remotePatterns: [
{ protocol: "https", hostname: "www.google.com", pathname: "**" },
{ protocol: "https", hostname: "images.example.com", pathname: "**" },
],
},Restart npm run dev afterwards.
Cause: home.image in content.tsx is /images/og/home.jpg, and that file is not in the repository.
Fix: add an image at public/images/og/home.jpg (or change home.image to an image you have).
Cause: /api/og/generate loads your avatar from meta.baseURL + person.avatar, and downloads the Geist font from Google Fonts on each request. If baseURL still points to the author's site, his avatar appears; if the font cannot be downloaded, the route fails with failed to load font data.
Fix: set meta.baseURL to your own deployed address, and make sure the server can reach fonts.googleapis.com.
Cause: given a url, OgCard asks /api/og/fetch for the preview and loads outside images through /api/og/proxy. This repository does not have those routes (they fetched any URL they were given), so the request fails, the browser console shows Error fetching og data, and the card renders nothing.
Fix: pass the preview yourself with the ogData prop (title, description, image, url) and leave out url, so the card does not call those routes.
Cause: every project screenshot is captured during the build. A slow site can take a while; the limit per page is 180 seconds (staticPageGenerationTimeout).
Fix: set screenshot: false on projects whose sites are slow or unreliable.
Check what the browser received:
| Message | Cause | Fix |
|---|---|---|
| "Incorrect password" with HTTP 401 | The password does not match PAGE_ACCESS_PASSWORD
|
Check for typos and extra spaces in .env.local
|
"Incorrect password", and the server log shows PAGE_ACCESS_PASSWORD environment variable is not set
|
The variable is missing (the API answered 500) | Set it in .env.local or your host, then restart npm run dev or redeploy |
That is expected: the authToken cookie lasts one hour.
protectedRoutes matches exact paths only. Add each path you want protected, for example "/work/my-project": true.
Cause: the start-up script in src/app/layout.tsx always starts from the visitor's saved choice or, if there is none, their system setting. It does not read style.theme.
Fix: to force a starting theme, edit the resolveTheme logic in that script.
Cause: your last choice is saved in localStorage under data-theme.
Fix: use the toggle in the header, or clear the site's data in your browser.
Do I need a database?
No. All content lives in files: site-data.tsx, content.tsx and the .mdx project files.
Do I have to use Vercel?
No. Any server with Node.js 22.17+ or 24+ can run npm run build and npm start. Vercel is simply the easiest place for the live screenshots. See Deployment.
Can I use Yarn or pnpm?
The repository ships package-lock.json, so npm is what it is set up and tested with.
How do I remove the live numbers?
Delete the %...% tokens from hero.subline, about.introDescription, the experience achievements and your project files, and write the numbers (or other words) yourself.
How do I add a new page?
Create src/app/<name>/page.tsx, add "/<name>": true to routes, and add a header button in src/components/Header.tsx if you want one.
How do I change the colours?
Change brand, accent and neutral in style in once-ui.config.ts. All allowed values are on Configuration.
Is there a blog?
Not in this repository. The settings and components for one (/blog route, Posts, ShareSection, RSS) exist, but there are no blog pages or posts.
Is the password protection secure? It is a light gate, fine for a draft page. It is checked in the browser and the cookie value is a fixed string. Do not use it for private information.
Can I use this for my own portfolio? Yes. It is MIT licensed: use it, change it, publish it; keep the license notice in your copy.
Where do I ask for help or report a bug? Open an issue on GitHub. See Contributing.
Personal Website by Umut Bayraktar · MIT License · Codeshare
Start
Reference
Go live
Community