koala73/worldmonitor · error · ConvexError
COMPANY_MONITORING_EVIDENCE_SUBJECTS_INVALID
Error message
COMPANY_MONITORING_EVIDENCE_SUBJECTS_INVALID
What it means
Thrown by canonicalSubjects in evidence.ts when the requestedCompanyIds array is empty or exceeds COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount. This is the first of three guards in canonicalSubjects that share the same error code; this one bounds the size of the evidence-ingestion subject set before any deduplication or lookup.
Source
Thrown at convex/companyMonitoring/evidence.ts:47
// companies. Reject a wider internal expansion before the first write so the
// receipt remains atomic and the mutation cannot exceed its scheduler budget.
const MAX_EXPANDED_EVIDENCE_ROWS = 25 * 25;
type EvidenceDoc = Doc<"companyMonitoringEvidence">;
function nextUpdatedAt(row: { updatedAt: number } | null | undefined, now: number) {
return Math.max(now, (row?.updatedAt ?? now - 1) + 1);
}
async function canonicalSubjects(
ctx: MutationCtx,
ownerAccountId: string,
requestedCompanyIds: string[],
) {
if (
requestedCompanyIds.length === 0 ||
requestedCompanyIds.length > COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount
) {
throw new ConvexError("COMPANY_MONITORING_EVIDENCE_SUBJECTS_INVALID");
}
const subjectIds = [...new Set(requestedCompanyIds)].sort();
if (subjectIds.length !== requestedCompanyIds.length) {
throw new ConvexError("COMPANY_MONITORING_EVIDENCE_SUBJECTS_INVALID");
}
const canonical = await Promise.all(subjectIds.map(async (companyId): Promise<EvidenceSubject> => {
const [company, claims] = await Promise.all([
ctx.db
.query("companyMonitoringCompanies")
.withIndex("by_account_companyId", (q) =>
q.eq("ownerAccountId", ownerAccountId).eq("companyId", companyId),
)
.unique(),
ctx.db
.query("companyMonitoringClaims")
.withIndex("by_account_company", (q) =>
q.eq("ownerAccountId", ownerAccountId).eq("companyId", companyId),
)View on GitHub (pinned to ffec79ac33)
Solutions
- Ensure the companyIds list is non-empty and at most COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount before calling ingest.
- If the provider returned more subjects than the cap, split the ingestion into multiple calls each within the limit, or drop out-of-cap subjects deliberately.
- Re-read the current maxCompaniesPerAccount value from the shared contract; do not hard-code it.
Example fix
// before
await ingest({ ownerAccountId, companyIds: allIds, evidence });
// after
const CAP = COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount;
const safeIds = allIds.slice(0, CAP);
if (safeIds.length === 0) throw new Error("no subjects");
await ingest({ ownerAccountId, companyIds: safeIds, evidence }); Defensive patterns
Strategy: validation
Validate before calling
const CAP = COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount;
if (companyIds.length === 0 || companyIds.length > CAP) {
throw new Error("subjects out of range");
} Type guard
function subjectsInRange(ids: string[], cap: number): boolean {
return ids.length > 0 && ids.length <= cap;
} Prevention
- Bound the subject list to maxCompaniesPerAccount before ingesting.
- Re-read the cap from the shared contract; do not hard-code it.
When it happens
Trigger: Calling ingestCompanyEvidenceForCompanyIds (or the ingestEvidenceForTest mutation) with an empty companyIds array or one longer than COMPANY_MONITORING_LIMITS.maxCompaniesPerAccount.
Common situations: Worker code forwarding an unbatched provider result that touched more companies than the account cap allows; a bug producing an empty subject list; exceeding the per-account company cap because the limit was lowered after companies were added.
Related errors
- COMPANY_MONITORING_EVIDENCE_BATCH_INVALID
- COMPANY_MONITORING_EVIDENCE_EXPANSION_INVALID
- INVALID_COMPANY_PATCH
- INVALID_COMPANY_MONITORING_COHORT
- COUNTRIES_LIMIT_EXCEEDED
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/94747c4ab355a858.
Report an issue: GitHub.