can1357/oh-my-pi · error · TypeError
sizeCalculation is required when a size limit is set
Error message
sizeCalculation is required when a size limit is set
What it means
When an LRUCache is given a size limit (maxSize or maxEntrySize > 0), it needs a sizeCalculation callback to determine each entry's size — the library cannot infer it. Constructing a size-bounded cache without that function throws this TypeError at construction time rather than failing later on the first set().
Source
Thrown at packages/utils/src/lru.ts:59
readonly #maxEntrySize: number;
readonly #sizeCalculation: ((value: V, key: K) => number) | undefined;
readonly #ttl: number;
readonly #updateAgeOnGet: boolean;
readonly #dispose: ((value: V, key: K, reason: DisposeReason) => void) | undefined;
#calculatedSize = 0;
/** Creates an empty cache. */
constructor(options: LRUCacheOptions<K, V>) {
this.#max = positiveInteger(options.max, "max");
this.#maxSize = positiveInteger(options.maxSize, "maxSize");
const explicitMaxEntrySize = positiveInteger(options.maxEntrySize, "maxEntrySize");
this.#maxEntrySize = explicitMaxEntrySize || this.#maxSize;
this.#ttl = positiveInteger(options.ttl, "ttl");
if (this.#max === 0 && this.#maxSize === 0 && this.#ttl === 0) {
throw new TypeError("At least one of max, maxSize, or ttl is required");
}
if ((this.#maxSize !== 0 || this.#maxEntrySize !== 0) && options.sizeCalculation === undefined) {
throw new TypeError("sizeCalculation is required when a size limit is set");
}
this.#sizeCalculation = options.sizeCalculation;
this.#updateAgeOnGet = options.updateAgeOnGet === true;
this.#dispose = options.dispose;
}
/** Number of entries, including stale entries not yet removed by `get`. */
get size(): number {
return this.#entries.size;
}
/** Aggregate calculated size of retained entries. */
get calculatedSize(): number {
return this.#calculatedSize;
}
/** Stores a value and makes it most recently used. */
set(key: K, value: V | undefined): this {View on GitHub (pinned to 9690622007)
Solutions
- Provide sizeCalculation: (value, key) => byteLength or similar when setting maxSize/maxEntrySize.
- If you don't need size bounding, remove maxSize/maxEntrySize and bound with max or ttl instead.
- For string/buffer caches a typical calculation is v => Buffer.byteLength(String(v)).
- Keep options objects in memory — don't serialize cache options through JSON.
Example fix
// before
const cache = new LRUCache({ maxSize: 1024 * 1024 }); // TypeError
// after
const cache = new LRUCache({
maxSize: 1024 * 1024,
sizeCalculation: (v: string) => Buffer.byteLength(v),
}); Defensive patterns
Strategy: validation
Validate before calling
function assertSizeConfig(o: { maxSize?: number; maxEntrySize?: number; sizeCalculation?: (v: unknown, k: unknown) => number }): void {
if ((o.maxSize || o.maxEntrySize) && typeof o.sizeCalculation !== "function") {
throw new TypeError("sizeCalculation function is required with maxSize/maxEntrySize");
}
} Type guard
function hasSizeCalculation(o: { maxSize?: number; maxEntrySize?: number; sizeCalculation?: unknown }): o is { sizeCalculation: (v: never, k: never) => number } & Record<string, unknown> {
return Boolean(o.maxSize || o.maxEntrySize) && typeof o.sizeCalculation === "function";
} Try / catch
try {
cache = new LRUCache(options);
} catch (err) {
if (err instanceof TypeError && err.message.includes("sizeCalculation is required")) {
logger.warn("Size-bounded LRU missing sizeCalculation; adding byte-length estimator");
cache = new LRUCache({ ...options, sizeCalculation: (v: unknown) => Math.max(1, Buffer.byteLength(String(v))) });
} else throw err;
} Prevention
- Keep cache options in memory — JSON round-trips drop functions like sizeCalculation.
- Pair every maxSize/maxEntrySize with its sizeCalculation in the same object literal.
- Add a constructor-options test that builds the cache so the error fires in CI, not production.
When it happens
Trigger: new LRUCache({ maxSize: 1024 }) with no sizeCalculation, new LRUCache({ maxEntrySize: 100 }) alone, or config-merge dropping the sizeCalculation key while keeping maxSize.
Common situations: Spreading options objects where functions were serialized/dropped (JSON round-trip of options), copy-pasted cache setup that kept maxSize but removed the callback, TypeScript type loosening via as any that bypassed the option type check.
Understand the failure class
Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.
Related errors
- ${name} must be a non-negative integer
- At least one of max, maxSize, or ttl is required
- sizeCalculation return invalid (expect positive integer)
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id wit
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c2cbba44a18a16bd.
Report an issue: GitHub.