{"record":{"id":"758e6465098a16cf","repo":"paperclipai/paperclip","slug":"list-maxlength-must-be-a-positive-safe-integer","errorCode":null,"errorMessage":"List maxLength must be a positive safe integer","messagePattern":"List maxLength must be a positive safe integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-state.ts","lineNumber":303,"sourceCode":"    }\n    throw this.casExhausted(\"set cache value if absent\");\n  }\n\n  async delete(key: string): Promise<void> {\n    await this.deleteCurrent(\"cache\", key);\n  }\n\n  async appendToList(\n    key: string,\n    value: unknown,\n    options?: { maxLength?: number; ttlMs?: number },\n  ): Promise<void> {\n    this.ensureConnected();\n    if (\n      options?.maxLength !== undefined &&\n      !(Number.isSafeInteger(options.maxLength) && options.maxLength > 0)\n    ) {\n      throw new Error(\"List maxLength must be a positive safe integer\");\n    }\n    const storedKey = storageKey(\"list\", key);\n    const expiresAt = this.expiryFromTtl(options?.ttlMs);\n    for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt += 1) {\n      const record = await this.persistence.read(this.scope, storedKey);\n      const prior =\n        record && !this.isExpired(record) ? decodeEnvelope(record, \"list\") : [];\n      if (!Array.isArray(prior)) throw new Error(\"Invalid Chat SDK list state\");\n      const appended = [...prior, value];\n      const next = options?.maxLength\n        ? appended.slice(-options.maxLength)\n        : appended;\n      if (\n        await this.compareAndSet(\n          storedKey,\n          record?.version ?? null,\n          \"list\",\n          next,","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-state.ts#L285-L321","documentation":"appendToList validates the optional options.maxLength: if supplied it must be a positive safe integer, since it caps list length during the CAS append loop. Non-integers, 0, negatives, NaN, and values beyond Number.MAX_SAFE_INTEGER are rejected before any persistence work.","triggerScenarios":"Passing { maxLength: 0 }, { maxLength: -10 }, { maxLength: 1.5 }, { maxLength: NaN }, or a value from unparsed/unvalidated config into appendToList(key, value, options).","commonSituations":"maxLength read from env/config as a string or unvalidated number; arithmetic producing fractional values (e.g. size/2); defaulting maxLength to 0 when unset.","solutions":["Validate before the call: Number.isSafeInteger(maxLength) && maxLength > 0","Coerce and round config-derived values with Math.round(Number(x)) then re-check","Use undefined (not 0) when no cap is desired"],"exampleFix":"// before\nawait state.appendToList(key, item, { maxLength: rawCap });\n// after\nconst maxLength = rawCap === undefined ? undefined : Math.round(Number(rawCap));\nif (maxLength !== undefined && !(Number.isSafeInteger(maxLength) && maxLength > 0)) {\n  throw new Error(`bad maxLength: ${rawCap}`);\n}\nawait state.appendToList(key, item, { maxLength });","handlingStrategy":"validation","validationCode":"if (maxLength !== undefined && !(Number.isSafeInteger(maxLength) && maxLength > 0)) throw new Error('maxLength must be a positive safe integer');","typeGuard":"function isPositiveSafeInt(v: unknown): v is number { return typeof v === 'number' && Number.isSafeInteger(v) && v > 0; }","tryCatchPattern":"try { await state.appendToList(key, item, { maxLength }); } catch (err) { if (/maxLength must be a positive safe integer/.test((err as Error).message)) { /* correct the option and retry */ } throw err; }","preventionTips":["Round and validate config-derived numeric options once at load time","Use undefined to signal 'no cap' rather than 0","Avoid passing raw string env values into numeric options"],"tags":["validation","list","argument-error"],"backgroundTag":"invalid-argument-value","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}