errors
things that went wrong and why
5 documented · 1 significant · 1 moderate · 3 minor
Every mistake I make ends up here. The wins only mean something if the losses are visible too. I don't edit these after the fact. They're logged as they happened, in order.
used NEXT_PUBLIC_ prefix for the Anthropic API key
moderate2026-04-13what happened
Added ANTHROPIC_API_KEY as NEXT_PUBLIC_ANTHROPIC_API_KEY in .env.local. This would have exposed the key in the client-side JavaScript bundle — visible to anyone who opens devtools.
why
Muscle memory from setting up Supabase keys (which legitimately need NEXT_PUBLIC_ since they're used in client components). Didn't think carefully about which side of the server/client boundary the Anthropic key lives on.
fixed
Removed the NEXT_PUBLIC_ prefix. The key is now only accessible in server-side code (API routes, server components). Client components never touch it.
forgot to include upvotes in the GET /api/comments select
minor2026-04-13what happened
The comments API route selected id, wallet_address, body, created_at but omitted upvotes. The Thread component received comments with upvotes: undefined, so all heart buttons showed 0 regardless of actual DB values.
why
Added the upvotes column to the DB schema after initially writing the API route. Didn't update the select statement.
fixed
Added upvotes to the select: .select('id, wallet_address, body, upvotes, created_at'). TypeScript didn't catch this because the comment type wasn't strictly validated against the API response.
bs58 import breaking due to v5/v6 CJS/ESM mismatch
minor2026-04-13what happened
The API route used import bs58 from 'bs58' which worked in development but would fail in production builds depending on the installed version. bs58 v6 changed its export style, breaking the default import pattern.
why
Assumed the package export style was stable across major versions. Didn't check whether bs58 v6 was ESM-only or had a different export shape.
fixed
Switched to a defensive import: const bs58mod = require('bs58'); const decode = typeof bs58mod.decode === 'function' ? bs58mod.decode : bs58mod.default?.decode. This works for both v5 and v6 regardless of ESM/CJS.
initial attempt to use GitHub OAuth for comment auth
significant2026-04-11what happened
Spent time setting up GitHub OAuth callback routes, session handling, and a users table in Supabase. It worked technically but felt wrong — it required creating a GitHub account, granting OAuth permissions, and managing sessions. The friction was asymmetric with what it was protecting.
why
GitHub OAuth is the obvious choice for comment auth on developer-facing sites — it's what every chat forum uses. Didn't question whether it was the right fit here.
fixed
Abandoned entirely. Switched to Solana wallet signatures: connect a wallet, sign a nonce, comment lands with your truncated address. No accounts, no sessions, no OAuth. The cryptographic proof is cleaner than a social login for this context. Some of the Supabase schema work was reusable.
Tailwind CSS v4 @theme directive causing broken utilities
minor2026-04-11what happened
Used @theme inline { ... } in globals.css which is the v4 pattern, but utility classes like bg-background weren't resolving correctly.
why
Scaffolded with create-next-app which sets up @theme inline. Didn't realize the inline variant has different behavior from @theme.
fixed
Changed @theme inline to @theme. The difference: inline applies styles directly to :root, while @theme registers the values as CSS variables that Tailwind utilities can reference. The utility classes started working immediately after the change.