koala73/worldmonitor · error
Worksheet JSON must be no larger than 64 KiB.
Error message
Worksheet JSON must be no larger than 64 KiB.
What it means
importOperationalWorksheet parses a pasted/uploaded worksheet JSON string and first enforces a size cap of MAX_OPERATIONAL_JSON_BYTES (64 KiB), measured as UTF-8 byte length via TextEncoder. Oversized text is rejected before JSON.parse to bound memory and abuse on the client.
Solutions
- Measure new TextEncoder().encode(text).length before importing and trim deliveries/fields to fit under 65536 bytes.
- Strip optional fields or extra whitespace/pretty-printing (minify the JSON) to shrink the payload.
- Split the dataset across multiple worksheet imports.
- Show a byte-counter in the import UI and warn before the user submits oversized text.
Example fix
// before
importOperationalWorksheet(prettyPrintedJson);
// after
const minified = JSON.stringify(JSON.parse(prettyPrintedJson));
if (new TextEncoder().encode(minified).length > 65536) throw new Error('Worksheet exceeds 64 KiB after minification.');
importOperationalWorksheet(minified); Defensive patterns
Strategy: validation
Validate before calling
const bytes = new TextEncoder().encode(text).length;
if (bytes > 65536) throw new Error(`Worksheet text is ${bytes} bytes; limit is 65536 (64 KiB).`); Try / catch
try {
const snapshot = importOperationalWorksheet(text);
} catch (err) {
if (err instanceof Error && err.message === 'Worksheet JSON must be no larger than 64 KiB.') {
showImportError('Import too large; remove extra deliveries or minify the JSON.');
} else throw err;
} Prevention
- Minify JSON (JSON.stringify(parsed)) before import to drop pretty-print whitespace.
- Check UTF-8 byte length (not .length) — multi-byte characters count double or more.
- Keep worksheets near the 30-delivery cap; they naturally stay far below 64 KiB.
When it happens
Trigger: Calling importOperationalWorksheet(text) where text's UTF-8 encoding exceeds 65536 bytes — e.g. a worksheet with thousands of delivery rows, embedded notes/base64 blobs, or a user pasting an entire file's contents including unrelated data.
Common situations: Multi-byte characters (CJK, emoji) inflating byte count well past the character count; an export from another tool that doesn't share the 30-delivery cap; concatenating multiple worksheet exports.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- batch exceeds ${COMPANY_MONITORING_LIMITS.maxImportBatchByte
- batch exceeds ${COMPANY_MONITORING_LIMITS.maxImportRows} row
- batch rows must share one clientImportId
- batch ordinals must be contiguous from 0
- Use at most 30 deliveries per list.
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/e071b161180db23c.
Report an issue: GitHub.
Appendix: source
Thrown at src/utils/operational-balance.ts:76
const date = dateAt(input.startDate, index);
const arrivals = round(deliveries.filter(row => row.date === date).reduce((sum, row) => sum + row.quantity, 0));
const available = round(stock + arrivals);
const unmetDemand = round(Math.max(0, demand - available));
stock = round(Math.max(0, available - demand));
return { day: index + 1, date, arrivals, demand, closingStock: stock, unmetDemand };
});
return { days, firstGapDay: days.find(day => day.unmetDemand > 0)?.day ?? null, totalUnmetDemand: round(days.reduce((sum, day) => sum + day.unmetDemand, 0)) };
};
const baseline = balance(input.deliveries, input.dailyDemand);
const alternative = balance([...input.deliveries, ...input.alternativeDeliveries], input.alternativeDailyDemand ?? input.dailyDemand);
const costsKnown = [...input.deliveries, ...input.alternativeDeliveries].every(row => row.costUsd !== null);
return { schema: 'worldmonitor-operational-worksheet/v1', input, baseline, alternative,
avoidedUnmetDemand: round(baseline.totalUnmetDemand - alternative.totalUnmetDemand),
additionalDeliveryCostUsd: costsKnown ? round(input.alternativeDeliveries.reduce((sum, row) => sum + row.costUsd!, 0)) : null };
}
export function importOperationalWorksheet(text: string): OperationalSnapshot {
if (new TextEncoder().encode(text).length > MAX_OPERATIONAL_JSON_BYTES) throw new Error('Worksheet JSON must be no larger than 64 KiB.');
const value = record(JSON.parse(text));
if (value.schema !== 'worldmonitor-operational-worksheet/v1') throw new Error('Unsupported worksheet format.');
return calculateOperationalBalance(value.input);
}
export function operationalExample(): OperationalInput {
return { operation: 'Example operation', basis: 'example', unit: 'units', startDate: '2026-09-10', horizonDays: 10, startingStock: 100, dailyDemand: 20,
deliveries: [{ date: '2026-09-13', quantity: 40, unit: 'units', costUsd: null }], alternativeDeliveries: [], alternativeDailyDemand: null };
}
View on GitHub (pinned to 7d06c8633d)