koala73/worldmonitor · error · BillingDenialError
${label} HTTP ${status} (${billingCode})
Error message
${label} HTTP ${status} (${billingCode}) What it means
claimProActivationPresentation() atomically re-checks server-side activation state and reserves one markerless presentation across devices; it needs both getConvexClient() and getConvexApi(). If either resolves null it throws 'Convex unavailable' before requireCurrentConvexUser or the payments.billing.claimProActivationPresentation mutation run. Null clients come from a missing VITE_CONVEX_URL or a ConvexClient constructor failure (Firefox 149/Linux degrades to null by design).
Source
Thrown at api/mcp/billing-denial.ts:107
this.status = 400;
this.violations = violations;
}
}
/**
* Throws BillingDenialError when a non-ok gateway response carries the
* billing-verification marker header. Detection is header-only, so callers
* that read the error body for detail can still consume it afterwards.
*/
export function throwIfBillingDenial(response: ToolFetchResponse, label: string): void {
if (response.ok) return;
const marker = response.headers?.get('X-Billing-Verification');
if (!marker || !BILLING_VERIFICATION_CODES.has(marker)) return;
// Distinguish a missing header from a present-but-zero value: Number(null)
// is 0 (finite), which would silently masquerade as an explicit 0s hint.
const retryHeader = response.headers?.get('Retry-After');
const rawRetryAfter = retryHeader == null ? Number.NaN : Number(retryHeader);
throw new BillingDenialError(
label,
response.status,
marker as BillingVerificationCode,
Number.isFinite(rawRetryAfter) ? rawRetryAfter : undefined,
);
}
function sanitizeViolationField(value: unknown): string | null {
if (typeof value !== 'string') return null;
const field = value.trim().slice(0, MAX_VIOLATION_FIELD_LEN);
return SAFE_VIOLATION_FIELD.test(field) ? field : null;
}
function sanitizeViolationDescription(value: unknown): string | null {
if (typeof value !== 'string') return null;
const description = value.replace(/\s+/g, ' ').trim().slice(0, MAX_VIOLATION_DESCRIPTION_LEN);
if (!description || UNSAFE_VIOLATION_DESCRIPTION.test(description)) return null;
return description;View on GitHub (pinned to a96956387a)
Solutions
- Set VITE_CONVEX_URL to the Convex deployment and rebuild
- Check the console for '[convex-client] ConvexClient constructor rejected:'
- Try Chrome to rule out the Firefox 149/Linux constructor bug
- Defer the activation-claim UI behind a client-availability check and show an env banner when null
Example fix
// before
const outcome = await claimProActivationPresentation(activationKey, claimNonce);
// 'Convex unavailable'
// after
if (!(await getConvexClient())) {
showEnvBanner('Convex is not configured; Pro activation cannot be claimed yet.');
return;
}
const outcome = await claimProActivationPresentation(activationKey, claimNonce); Defensive patterns
Strategy: validation
Validate before calling
if (!(await getConvexClient())) {
showEnvBanner('Convex is not configured; Pro activation cannot be claimed yet.');
return;
}
await claimProActivationPresentation(activationKey, claimNonce); Try / catch
try {
const outcome = await claimProActivationPresentation(activationKey, claimNonce);
} catch (e) {
if (e instanceof Error && e.message === 'Convex unavailable') showEnvBanner('Backend not configured.');
else throw e;
} Prevention
- Check Convex client availability before rendering activation-claim UI
- Ensure VITE_CONVEX_URL is set in every build that can show Pro activation
- Watch for the constructor-rejection console warning on Firefox 149/Linux
When it happens
Trigger: App built without VITE_CONVEX_URL; browser-side ConvexClient constructor rejection; client init failed mid-boot when the user attempts to claim Pro activation.
Common situations: Fresh clone without .env.local; staging/preview build missing env; browser-specific interop bug; tests without a Convex client factory.
Related errors
- Webhook URL must not point to a private/local address
- MCP_INTERNAL_HMAC_SECRET not configured
- BUSINESS_NOT_ACTIVE
- PRO_REQUIRED
- INCOMPATIBLE_DELIVERY
AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-21).
Data as JSON: /api/errors/5be453fce8c03b59.
Report an issue: GitHub.