koala73/worldmonitor · error · ConvexError
COMPANY_MONITORING_EVIDENCE_BATCH_INVALID
Error message
COMPANY_MONITORING_EVIDENCE_BATCH_INVALID
What it means
Thrown by ingestCompanyEvidenceForCompanyIds when the input.evidence array is empty or larger than MAX_INGESTION_ROWS (100). This bounds the per-call ingestion size so each mutation stays within its scheduler budget; an empty batch is rejected because there is nothing to ingest.
Source
Thrown at convex/companyMonitoring/evidence.ts:364
referenceEvidenceFingerprints: [],
referenceCount: 0,
referencesTruncated: false,
evidenceRevision: existing.evidenceRevision + 1,
evidenceSnapshotDigest: emptyEvidenceSnapshotDigest,
updatedAt: now,
});
}
export async function ingestCompanyEvidenceForCompanyIds(
ctx: MutationCtx,
input: {
ownerAccountId: string;
companyIds: string[];
evidence: ProviderEvidence[];
},
) {
if (input.evidence.length === 0 || input.evidence.length > MAX_INGESTION_ROWS) {
throw new ConvexError("COMPANY_MONITORING_EVIDENCE_BATCH_INVALID");
}
const account = await ctx.db
.query("companyMonitoringAccounts")
.withIndex("by_logicalAccountId", (q) => q.eq("logicalAccountId", input.ownerAccountId))
.unique();
if (!account || account.lifecycle !== "entitled" || account.terminalReason) {
throw new ConvexError("COMPANY_MONITORING_ACCOUNT_INACTIVE");
}
const subjects = await canonicalSubjects(ctx, input.ownerAccountId, input.companyIds);
const normalized = await normalizeCompanyEvidence({
ownerAccountId: input.ownerAccountId,
subjects,
evidence: input.evidence,
now: Date.now(),
});
if (normalized.evidence.length > MAX_EXPANDED_EVIDENCE_ROWS) {
throw new ConvexError("COMPANY_MONITORING_EVIDENCE_EXPANSION_INVALID");
}View on GitHub (pinned to ffec79ac33)
Solutions
- Chunk provider evidence into batches of at most MAX_INGESTION_ROWS before calling ingest.
- Skip the call entirely when the evidence list is empty.
- Re-read MAX_INGESTION_ROWS from the module rather than hard-coding 100.
Example fix
// before
await ingest({ ownerAccountId, companyIds, evidence: allEvidence });
// after
const BATCH = 100;
for (let i = 0; i < allEvidence.length; i += BATCH) {
await ingest({ ownerAccountId, companyIds, evidence: allEvidence.slice(i, i + BATCH) });
} Defensive patterns
Strategy: validation
Validate before calling
if (evidence.length === 0) return { status: "noop" };
if (evidence.length > 100) throw new Error("evidence batch exceeds 100 rows");
await ingest(...); Type guard
function batchWithinLimit(rows: unknown[], limit = 100): boolean {
return rows.length > 0 && rows.length <= limit;
} Prevention
- Chunk provider receipts into batches of MAX_INGESTION_ROWS.
- Skip ingestion when there is nothing to ingest.
When it happens
Trigger: Calling ingestion with evidence.length === 0 or evidence.length > 100 (MAX_INGESTION_ROWS).
Common situations: Worker batching a full Exa/X receipt that exceeds 100 rows without chunking; a no-op call with an empty evidence list; a normalization bug collapsing all rows away.
Related errors
- COMPANY_MONITORING_EVIDENCE_SUBJECTS_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/21ba11c6e25a15f7.
Report an issue: GitHub.