koala73/worldmonitor · error · ConvexError
INVALID_
Error message
INVALID_${field.toUpperCase()} What it means
Dynamic validation sentinel from normalizeRequestId in the Company Monitoring shared helpers: a request-identifier field (the embedded INVALID_<FIELD> names it, e.g. INVALID_REQUESTID) failed validation — empty after trim, over length, or containing control/invisible Unicode characters matched by REQUEST_CONTROL. The input at fault is the request-correlation identifier supplied by the client.
Solutions
- Regenerate the request id client-side: a fresh UUID or Crockford-style id with no control or invisible characters
- Validate the id (non-empty, within length, no control chars) before submitting
- If the client builds ids from user text, sanitize or reject that copy source
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at convex/companyMonitoring/_shared.ts:24 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/2d9c9349e2790c15.
Report an issue: GitHub.
Appendix: source
Thrown at convex/companyMonitoring/_shared.ts:24
type NormalizedMonitoredCompanyInput,
} from "../../shared/company-monitoring-contract";
export const COMPANY_LIMIT = COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount;
export const COMPANY_MONITORING_CLAIM_POLICY_VERSION = 1;
const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
const REQUEST_CONTROL = /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u180e\u200b-\u200f\u2028-\u202e\u2060-\u206f\ufeff\ufff9-\ufffb]/u;
type CompanyMonitoringCtx = MutationCtx | QueryCtx;
export function hasCurrentCompanyMonitoringClaimPolicy(
account: Pick<Doc<"companyMonitoringAccounts">, "claimPolicyVersion">,
): boolean {
return (account.claimPolicyVersion ?? 0) >= COMPANY_MONITORING_CLAIM_POLICY_VERSION;
}
export function normalizeRequestId(value: string, field = "clientRequestId"): string {
if (typeof value !== "string" || REQUEST_CONTROL.test(value)) {
throw new ConvexError(`INVALID_${field.toUpperCase()}`);
}
const normalized = value.normalize("NFC").trim();
if (!normalized || new TextEncoder().encode(normalized).byteLength > 64) {
throw new ConvexError(`INVALID_${field.toUpperCase()}`);
}
return normalized;
}
export async function fingerprint(value: unknown): Promise<string> {
const bytes = new TextEncoder().encode(JSON.stringify(value));
const digest = await crypto.subtle.digest("SHA-256", bytes);
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
}
export function randomFence(): string {
const bytes = new Uint8Array(32);
crypto.getRandomValues(bytes);
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");View on GitHub (pinned to eeab0a219f)