koala73/worldmonitor · error · ConvexError
EMPTY_INPUT
EMPTY_INPUT
Error message
EMPTY_INPUT
What it means
Guard in mergeAnonymousLocal: args.countries is an empty array, so there is nothing to merge from the anonymous local state. Thrown as a typed ConvexError so callers can skip the merge instead of performing a pointless authenticated mutation.
Solutions
- Skip calling mergeAnonymousLocal when the local countries list is empty
- Catch EMPTY_INPUT client-side and treat it as a no-op success
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at convex/followedCountries.ts:497 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/ff1f42b9493b25d4.
Report an issue: GitHub.
Appendix: source
Thrown at convex/followedCountries.ts:497
*
* Resolves Codex-deepening round-1 P0 (server-side cap on merge) and
* round-2 P1 (canonicalize duplicates before counting). Free users with
* existingCount >= LIMIT accept zero new rows — never silently grow above
* the cap during merge. (Grandfathering above-cap rows on PRO→free
* downgrade is a separate concern handled by NOT auto-deleting on
* downgrade; merge is the FIRST sign-in and has no PRO history to
* grandfather.)
*/
export const mergeAnonymousLocal = mutation({
args: { countries: v.array(v.string()) },
handler: async (ctx, args): Promise<MergeAnonymousLocalResult> => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new ConvexError({ kind: "UNAUTHENTICATED" });
const userId = identity.subject;
// Step 2: empty-input guard.
if (args.countries.length === 0) {
throw new ConvexError({ kind: "EMPTY_INPUT" });
}
// Step 3: defensive upper-bound on input length.
if (args.countries.length > MAX_MERGE_INPUT) {
throw new ConvexError({
kind: "INPUT_TOO_LARGE",
max: MAX_MERGE_INPUT,
received: args.countries.length,
});
}
// Step 4: ISO-2 registry filter; collect droppedInvalid in input order.
const droppedInvalid: string[] = [];
const validInputs: string[] = [];
for (const code of args.countries) {
if (isValidIso2(code)) {
validInputs.push(code);
} else {View on GitHub (pinned to eeab0a219f)