koala73/worldmonitor · warning
buildAuthHeaders: free-tier context has no credentials — a f
Error message
buildAuthHeaders: free-tier context has no credentials — a free-tier tool must not call a credentialed downstream
What it means
requireSignedInUserId(action) is the billing service's shared guard: it reads getCurrentClerkUser()?.id and throws `Sign in to ${action}.` (e.g., 'Sign in to claim Pro activation.') when no Clerk session exists. The action string names the exact billing operation, so the message tells the developer which gated flow fired. No billing mutation or Convex call is attempted.
Source
Thrown at api/mcp/auth.ts:137
url: string,
body: BodyInit | null | undefined,
): Promise<Record<string, string>> {
if (context.kind === 'env_key' || context.kind === 'user_key') {
// user_key (#4859): the downstream REST gateway validates the raw key
// itself (Convex hash lookup + the #4611 apiAccess gate + per-account
// limits), so usage attributes to the key owner exactly like a direct
// REST call — no internal-HMAC identity smuggling needed.
return { 'X-WorldMonitor-Key': context.apiKey };
}
if (context.kind === 'free') {
// U7: a free-tier context has no principal to authenticate as, so there is
// nothing honest to sign. Throwing is the fail-closed choice — the
// alternative (falling through to the `pro` HMAC branch below) would mint
// an internally-trusted signature for an anonymous caller, which is the
// one outcome the free tier must never produce. A free-tier tool that
// reaches here is misconfigured: it declared `_freeTier` while calling a
// credentialed downstream.
throw new Error('buildAuthHeaders: free-tier context has no credentials — a free-tier tool must not call a credentialed downstream');
}
// context.kind === 'pro'
const secret = process.env.MCP_INTERNAL_HMAC_SECRET ?? '';
if (!secret) {
// Should never happen in production (deploy gate at U10) — surface as
// an error so the tool fetch fails fast rather than silently 401-ing
// at the gateway with a confusing "invalid_internal_mcp_signature".
throw new Error('MCP_INTERNAL_HMAC_SECRET not configured');
}
const signed = await signInternalMcpRequest({
method,
url,
body,
userId: context.userId,
secret,
});
return buildInternalMcpHeaders(signed);
}View on GitHub (pinned to a96956387a)
Solutions
- Sign in and retry the billing action
- Ensure Clerk is fully loaded before invoking billing flows
- Gate billing buttons on auth state so the call never fires signed-out
- Check ClerkProvider/publishable key configuration if the user should be signed in
Example fix
// before
const status = await claimProActivationPresentation(activationKey, claimNonce);
// 'Sign in to claim Pro activation.'
// after
if (!getCurrentClerkUser()?.id) {
openSignIn();
return;
}
const status = await claimProActivationPresentation(activationKey, claimNonce); Defensive patterns
Strategy: validation
Validate before calling
if (!getCurrentClerkUser()?.id) { openSignIn(); return; }
const outcome = await claimProActivationPresentation(activationKey, claimNonce); Type guard
const hasActiveClerkUser = (u: { id: string } | null | undefined): u is { id: string } =>
typeof u?.id === 'string' && u.id.length > 0; Try / catch
try {
await billingOperation();
} catch (e) {
if (e instanceof Error && e.message.startsWith('Sign in to ')) openSignIn();
else throw e;
} Prevention
- Route all billing UI through live auth state; the action name in the message identifies the flow
- Do not call billing functions during the Clerk loading window
- Prefix-matching 'Sign in to ' covers every current and future billing action string
When it happens
Trigger: Invoking any billing operation routed through requireSignedInUserId (such as claimProActivationPresentation) while signed out, after session expiry, before Clerk loads, or with ClerkProvider misconfigured.
Common situations: Billing UI rendered from cached state after logout; expired sessions on long-lived dashboards; dev builds without Clerk env vars.
Related errors
- Webhook URL must use HTTPS
- Sign in to view your brief.
- MCP_INTERNAL_HMAC_SECRET not configured
- PRO_REQUIRED
- UNAUTHENTICATED
AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-21).
Data as JSON: /api/errors/d3a74afb70c64ba2.
Report an issue: GitHub.