koala73/worldmonitor · error · ConvexError
INVALID_NAME
INVALID_NAME
Error message
INVALID_NAME
What it means
createEmbedKey requires a non-blank human-readable key name: `args.name.trim()` must be truthy. ConvexError("INVALID_NAME") is thrown for an empty string or a string of only whitespace. This runs after the entitlement gate and before prefix/hash validation.
Solutions
- Pass a non-empty name with at least one non-whitespace character, e.g. "Marketing site widget".
- Validate in the form/UI before invoking the mutation: require name.trim().length > 0.
- If the value comes from user input, trim it client-side before sending so stored and validated forms agree.
Example fix
// before
await api.embedKeys.createEmbedKey({ name: " ", keyPrefix, keyHash });
// after
const name = formValue.trim();
if (!name) throw new Error("Key name is required");
await api.embedKeys.createEmbedKey({ name, keyPrefix, keyHash }); Defensive patterns
Strategy: validation
Validate before calling
const name = rawName.trim();
if (!name) throw new Error("Embed key name is required"); Type guard
function hasNonEmptyName(name: unknown): name is string {
return typeof name === "string" && name.trim().length > 0;
} Try / catch
try {
await api.embedKeys.createEmbedKey({ ...args, name: args.name.trim() });
} catch (e) {
if (e instanceof ConvexError && e.data === "INVALID_NAME") {
// mark the name field required in the form
} else throw e;
} Prevention
- Mark the name input required and block submit when name.trim() is empty
- Trim client-side before sending so validation and stored value match
- Never initialize the form field to whitespace-only defaults
When it happens
Trigger: Calling createEmbedKey with name: "" or name: " " (whitespace-only), or with the name field omitted/undefined when the client bypasses the v.string() arg validation with a hand-built request.
Common situations: A dashboard form submitted without the display-name field filled in; form state initialized to "" and never bound; trimming happening only on the server so a whitespace-pasted value reaches the mutation; automated scripts sending minimal payloads.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/7c9d4dada3fd82d3.
Report an issue: GitHub.
Appendix: source
Thrown at convex/embedKeys.ts:86
.first();
// Merge before gating, unlike createApiKey. `apiAccess` has existed since
// the first entitlement row, so reading it raw is safe; `embedAccess` is
// new, so EVERY row written before this deploy omits it and the predicate
// is fail-closed on `undefined`. Gating on the stored value alone would
// lock every existing paid subscriber out of the feature until a Dodo
// billing event happened to rewrite their row.
const merged = entitlement
? {
features: mergeEntitlementFeatures(entitlement.planKey, entitlement.features),
validUntil: entitlement.validUntil,
}
: null;
if (!hasAccountEmbedAccess(identity?.plan, merged, Date.now())) {
throw new ConvexError("EMBED_ACCESS_REQUIRED");
}
if (!args.name.trim()) {
throw new ConvexError("INVALID_NAME");
}
if (!/^wme_[a-f0-9]{5}$/.test(args.keyPrefix)) {
throw new ConvexError("INVALID_PREFIX");
}
if (!/^[a-f0-9]{64}$/.test(args.keyHash)) {
throw new ConvexError("INVALID_HASH");
}
const allowedOrigins = normalizeAllowedOrigins(args.allowedOrigins);
const active = await ctx.db
.query("embedKeys")
.withIndex("by_userId_revokedAt", (q) =>
q.eq("userId", userId).eq("revokedAt", undefined),
)
.collect();
if (active.length >= MAX_EMBED_KEYS_PER_USER) {
throw new ConvexError("KEY_LIMIT_REACHED");
}View on GitHub (pinned to 7d06c8633d)