Skip to content

fix(app): /verify and /r/... 500 in production from publicConfig() - #26

Merged
YazarAyobami merged 1 commit into
mainfrom
fix/verify-publicconfig-crash
Oct 8, 2026
Merged

YazarAyobami merged 1 commit into
mainfrom
fix/verify-publicconfig-crash

Conversation

@abrcrmb

@abrcrmb abrcrmb commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

What and why

Production bug (reported by the owner): /verify and /r/[txHash]/[eventIndex] return 500 on the live site, even though the build and local test suite were green. Root cause: publicConfig() validates the entire shared PublicConfig schema, including NEXT_PUBLIC_INDEXER_URL, which genuinely isn't set in this Vercel project (no indexer deployed yet, M2-18). /send, /request, and /payee happen to never hit that call, because they only reach publicConfig() after a successful indexer fetch (guarded by a try/catch around listPayees()); my new receipt pages call it unconditionally just to label the asset for display, with no such guard, so it throws on every request.

Changes

  • app/r/[txHash]/[eventIndex]/useReceiptPage.ts, app/verify/useVerifyForm.ts: wrap the publicConfig() call in try/catch, degrading usdc to null on failure.
  • components/receipts/ReceiptResult.tsx: usdc prop is now { contractId, issuer } | null; the amount display falls back to no asset label when usdc (or lock) is unavailable, reusing the fallback that already existed for a missing lock.

Hard rules / invariants touched

None. Display-only fallback; doesn't touch verifyReceipt's actual verification result or the "Payment to verified payee" gating.

Tests

pnpm lint, pnpm typecheck, pnpm test (93/93), pnpm build all green. Reproduced the exact failure locally first: ran the dev server with the real .env.local (which has no NEXT_PUBLIC_INDEXER_URL, matching production) and hit /verify and /r/<hash>/0 directly, both 500 before the fix; both 200 after it, before redeploying to production.

Docs / ADR

None needed.

Roadmap

No row status change (M3-13 stays DONE; this is a bugfix, not new scope). Changelog entry added.

Assumptions and open questions

The underlying tension remains: publicConfig()'s "fail loudly on any missing field" design (its own code comment) means any future code that touches it without an indexer-fetch guard will hit the same class of bug until NEXT_PUBLIC_INDEXER_URL is actually set (M2-18) or NEXT_PUBLIC_INDEXER_URL is made optional in lib/config.ts's schema. Didn't change that schema here since it's a shared contract touching every page; flagging it rather than changing it unilaterally.

Given production was actively broken, I deployed this fix to kinlock-app.vercel.app via vercel --prod as soon as it was locally verified, ahead of this PR being merged. main should be fast-forwarded to match once this merges.

Both pages called publicConfig() unconditionally just to label the
asset for display. That validates the whole shared config, including
NEXT_PUBLIC_INDEXER_URL, which isn't set in this deployment (no
indexer yet, M2-18). Neither page needs the indexer at all. Wrapped
the call in try/catch, degrading to no asset label on failure, same
as the existing fallback for a missing lock.
@abrcrmb
abrcrmb requested a review from a team as a code owner October 8, 2026 11:13
@YazarAyobami
YazarAyobami merged commit 6244b89 into main Oct 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants