koala73/worldmonitor · error · ConvexError
UNAUTHENTICATED
UNAUTHENTICATED
Error message
UNAUTHENTICATED
What it means
Thrown at the top of the setAlertRules mutation handler when ctx.auth.getUserIdentity() returns null — i.e. no authenticated Clerk session. The message is the bare string 'UNAUTHENTICATED' (no structured code), surfaced as a ConvexError so the client receives it instead of a generic 500.
Source
Thrown at convex/alertRules.ts:209
export const setAlertRules = mutation({
args: {
variant: v.string(),
enabled: v.boolean(),
eventTypes: v.array(v.string()),
sensitivity: v.optional(sensitivityValidator),
channels: v.array(channelTypeValidator),
aiDigestEnabled: v.optional(v.boolean()),
// Optional country-scope (ISO-3166 alpha-2). Omit to preserve existing.
// Pass [] to explicitly reset to "all countries". Pass [...] to restrict.
countries: v.optional(v.array(v.string())),
// Optional watchlist ticker-scope (#4922 U3). Omit to preserve existing;
// [] resets. Unlike countries, [] means "no watchlist story alerts".
tickers: v.optional(v.array(v.string())),
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new ConvexError("UNAUTHENTICATED");
const userId = identity.subject;
await assertProEntitlement(ctx, userId);
const existing = await ctx.db
.query("alertRules")
.withIndex("by_user_variant", (q) =>
q.eq("userId", userId).eq("variant", args.variant),
)
.unique();
const pair = resolveEffectivePair({
incomingSensitivity: args.sensitivity,
existing: existing ?? undefined,
});
assertCompatibleDeliveryMode(pair);
const normalizedCountries = args.countries !== undefined
? normalizeCountries(args.countries)View on GitHub (pinned to ffec79ac33)
Solutions
- Ensure the Convex client has a valid Clerk session before invoking the mutation (await auth state readiness).
- Gate the UI call site behind a signed-in check so the mutation is only called when isAuthenticated is true.
- On receipt of this error, route the user to sign-in rather than retrying blindly.
Example fix
// before
useMutation(api.alertRules.setAlertRules)(args); // fires before auth resolves
// after
const { isSignedIn } = useUser();
const setAlertRules = useMutation(api.alertRules.setAlertRules);
if (isSignedIn) setAlertRules(args); Defensive patterns
Strategy: type-guard
Validate before calling
// Ensure auth is resolved before calling the mutation.
const identity = await convex.auth.getUserIdentity();
if (!identity) {
// route to sign-in
return;
}
await setAlertRules(args); Type guard
function isSignedIn(user): user is { subject: string } {
return !!user && typeof user.subject === 'string';
} Try / catch
try {
await setAlertRules(args);
} catch (e) {
if (e instanceof ConvexError && e.message === 'UNAUTHENTICATED') {
// session expired — re-authenticate, do not blind-retry
} else throw e;
} Prevention
- Gate every setAlertRules call site behind useUser().isSignedIn.
- Await Convex auth readiness on mount before enabling the submit action.
- On UNAUTHENTICATED, route to sign-in rather than retrying in a loop.
When it happens
Trigger: Calling the setAlertRules Convex mutation without a valid Clerk JWT in the auth context; calling after session expiry but before token refresh; calling from a context where the Convex client was not configured with an auth provider.
Common situations: Token-expired race during sign-out/sign-in transitions; a page that mounts the mutation call before the auth provider has resolved; misconfigured ConvexReactClient missing setAuth(); a bot or script hitting the mutation without credentials.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/1bdfadb9895cc430.
Report an issue: GitHub.