paperclipai/paperclip · error

Queue maxSize must be a positive safe integer

Error message

Queue maxSize must be a positive safe integer

What it means

enqueue validates maxSize (the queue capacity for a thread) must be a positive safe integer before reading and CAS-updating the stored queue. Zero, negatives, non-integers, and NaN/Infinity cannot form a valid bounded queue and are rejected.

Source

Thrown at server/src/services/chat-sdk-state.ts:346

    throw this.casExhausted("append list value");
  }

  async getList<T = unknown>(key: string): Promise<T[]> {
    const current = await this.readLive("list", key);
    if (!current) return [];
    if (!Array.isArray(current.value))
      throw new Error("Invalid Chat SDK list state");
    return current.value as T[];
  }

  async enqueue(
    threadId: string,
    entry: QueueEntry,
    maxSize: number,
  ): Promise<number> {
    this.ensureConnected();
    if (!(Number.isSafeInteger(maxSize) && maxSize > 0)) {
      throw new Error("Queue maxSize must be a positive safe integer");
    }
    const key = storageKey("queue", threadId);
    for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt += 1) {
      const record = await this.persistence.read(this.scope, key);
      const prior =
        record && !this.isExpired(record)
          ? decodeEnvelope(record, "queue")
          : [];
      if (!Array.isArray(prior))
        throw new Error("Invalid Chat SDK queue state");
      const now = this.now().getTime();
      const live = (prior as QueueEntry[]).filter(
        (item) => item.expiresAt > now,
      );
      const next = [...live, entry].slice(-maxSize);
      const expiresAt = new Date(
        Math.max(...next.map((item) => item.expiresAt)),
      );

View on GitHub (pinned to 01ad858492)

Solutions

  1. Validate first: Number.isSafeInteger(maxSize) && maxSize > 0
  2. Coerce config with Math.round(Number(raw)) and re-validate
  3. Omit/throw on unset capacity instead of passing 0

Example fix

// before
await queue.enqueue(threadId, entry, Number(env.QUEUE_MAX));
// after
const maxSize = Math.round(Number(env.QUEUE_MAX));
if (!(Number.isSafeInteger(maxSize) && maxSize > 0)) throw new Error(`QUEUE_MAX invalid: ${env.QUEUE_MAX}`);
await queue.enqueue(threadId, entry, maxSize);
Defensive patterns

Strategy: validation

Validate before calling

if (!(Number.isSafeInteger(maxSize) && maxSize > 0)) throw new Error('maxSize must be a positive safe integer');

Type guard

function isPositiveSafeInt(v: unknown): v is number { return typeof v === 'number' && Number.isSafeInteger(v) && v > 0; }

Try / catch

try { await queue.enqueue(threadId, entry, maxSize); } catch (err) { if (/Queue maxSize must be a positive safe integer/.test((err as Error).message)) { maxSize = DEFAULT_QUEUE_MAX; return queue.enqueue(threadId, entry, maxSize); } throw err; }

Prevention

When it happens

Trigger: Calling enqueue(threadId, entry, 0), a negative size, a fractional size, or a size sourced from unvalidated config/env; passing NaN after a failed Number() parse.

Common situations: Queue capacity from an env var parsed without validation; division producing fractional values; a misconfigured default of 0 interpreted as 'unlimited' by the caller but rejected by the API.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/1cb66d4a324aadfb. Report an issue: GitHub.