koala73/worldmonitor · error · Error
batch ordinals must be contiguous from 0
Error message
batch ordinals must be contiguous from 0
What it means
Thrown by normalizeCompanyImportBatch() when the sorted rows' ordinal values do not form an exact 0-based sequence. After sorting by ordinal, each row at index i must have ordinal === i, which rejects gaps, duplicates, and 1-based numbering alike.
Source
Thrown at shared/company-monitoring-contract.ts:319
if (utf8Bytes(JSON.stringify(normalized)) > COMPANY_MONITORING_LIMITS.maxImportRowBytes) {
throw new Error(`row exceeds ${COMPANY_MONITORING_LIMITS.maxImportRowBytes} bytes`);
}
return normalized;
}
export function normalizeCompanyImportBatch(inputs: CompanyImportRowInput[]): NormalizedCompanyImportRow[] {
if (!Array.isArray(inputs)) throw new Error('import batch must be a list');
if (inputs.length === 0) throw new Error('import batch requires at least one row');
if (inputs.length > COMPANY_MONITORING_LIMITS.maxImportRows) {
throw new Error(`batch exceeds ${COMPANY_MONITORING_LIMITS.maxImportRows} rows`);
}
const normalized = inputs.map(normalizeCompanyImportRow).sort((left, right) => left.ordinal - right.ordinal);
const importId = normalized[0]?.clientImportId;
for (let index = 0; index < normalized.length; index += 1) {
const row = normalized[index]!;
if (row.clientImportId !== importId) throw new Error('batch rows must share one clientImportId');
if (row.ordinal !== index) throw new Error('batch ordinals must be contiguous from 0');
}
if (utf8Bytes(JSON.stringify(normalized)) > COMPANY_MONITORING_LIMITS.maxImportBatchBytes) {
throw new Error(`batch exceeds ${COMPANY_MONITORING_LIMITS.maxImportBatchBytes} bytes`);
}
return normalized;
}
export function assertCompanyMonitoringPayloadSize(byteLength: number): void {
if (!Number.isSafeInteger(byteLength) || byteLength < 0) throw new Error('request byte length is invalid');
if (byteLength > COMPANY_MONITORING_LIMITS.maxRequestBytes) {
throw new Error(`request exceeds ${COMPANY_MONITORING_LIMITS.maxRequestBytes} bytes`);
}
}
export function assertCompanyMonitoringAccountContext(
context: { ownerAccountId?: string } | null | undefined,
): string {
const ownerAccountId = context?.ownerAccountId;View on GitHub (pinned to eeab0a219f)
Solutions
- Renumber the batch 0..n-1 immediately before calling normalizeCompanyImportBatch(), after any filtering or deletion
- If ordinals arrive 1-based from user data, subtract 1 during row normalization
- Pre-validate: rows.every((r, i) => r.ordinal === i) after sorting by ordinal, and fail fast in the UI with the offending index
Example fix
// before
const rows = csvLines.map((line, i) => ({ ...line, ordinal: i + 1 })); // 1-based from spreadsheet
const normalized = normalizeCompanyImportBatch(rows); // throws: ordinals must be contiguous from 0
// after
const rows = csvLines.map((line, i) => ({ ...line, ordinal: i })); // 0-based, contiguous
const normalized = normalizeCompanyImportBatch(rows); Defensive patterns
Strategy: validation
Validate before calling
const rows = rawRows
.filter(isValidRow)
.sort((a, b) => a.ordinal - b.ordinal)
.map((r, i) => ({ ...r, ordinal: i })); // resequence 0..n-1 after filter+sort
if (!rows.every((r, i) => r.ordinal === i)) throw new Error('ordinal resequencing failed'); Type guard
function hasContiguousOrdinals(rows: { ordinal: number }[]): boolean {
const sorted = [...rows].sort((a, b) => a.ordinal - b.ordinal);
return sorted.every((r, i) => r.ordinal === i);
} Try / catch
catch (e) { if (e instanceof Error && e.message === 'batch ordinals must be contiguous from 0') resequenceAndRetry(); else throw e; } Prevention
- Treat ordinals as array position, not as user data — always renumber after edits
- Subtract 1 from 1-based spreadsheet row numbers during ingestion
- Beware duplicate ordinals from parallel workers appending rows — build the batch in one pass
When it happens
Trigger: Sending ordinals 1..N from user-facing or spreadsheet data that is 1-based; filtering out invalid rows client-side but not renumbering the survivors, leaving gaps; duplicate ordinals from a mapping bug; an ordinal >= maxImportRows (100) surviving the earlier per-row check.
Common situations: CSV importers that pass through the file's row number as ordinal; UI code that deletes a row from a draft batch without resequencing; two async workers appending rows with overlapping counters.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- batch exceeds ${COMPANY_MONITORING_LIMITS.maxImportRows} row
- batch rows must share one clientImportId
- batch exceeds ${COMPANY_MONITORING_LIMITS.maxImportBatchByte
- invalid ${kind} logical ID
- get_intel_timeline requires at least one of domain ("conflic
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/995f6554f4776d12.
Report an issue: GitHub.