{"record":{"id":"5be9c911fa8560fe","repo":"linshenkx/prompt-optimizer","slug":"image-storage-quota-exceeded-projected-count-ne-5be9c9","errorCode":null,"errorMessage":"Image storage quota exceeded: projected count ${nextCount} exceeds maxCount ${config.maxCount}","messagePattern":"Image storage quota exceeded: projected count (.+?) exceeds maxCount (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/ui/src/utils/image-asset-storage.ts","lineNumber":192,"sourceCode":"  }\n\n  const stats = typeof storageService.getStorageStats === 'function'\n    ? await storageService.getStorageStats()\n    : null\n\n  if (!stats) {\n    return\n  }\n\n  const nextCount = stats.count + 1\n  const nextTotalBytes = stats.totalBytes + Math.floor(payload.b64.length * 0.75)\n\n  if (\n    typeof config.maxCount === 'number' &&\n    Number.isFinite(config.maxCount) &&\n    nextCount > config.maxCount\n  ) {\n    throw new Error(\n      `Image storage quota exceeded: projected count ${nextCount} exceeds maxCount ${config.maxCount}`,\n    )\n  }\n\n  if (\n    typeof config.maxCacheSize === 'number' &&\n    Number.isFinite(config.maxCacheSize) &&\n    nextTotalBytes > config.maxCacheSize\n  ) {\n    throw new Error(\n      `Image storage quota exceeded: projected size ${nextTotalBytes} exceeds maxCacheSize ${config.maxCacheSize}`,\n    )\n  }\n}\n\nexport const persistImagePayloadAsAssetId = async (\n  opts: PersistImagePayloadOptions,\n): Promise<string | null> => {","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/ui/src/utils/image-asset-storage.ts#L174-L210","documentation":"assertStorageQuotaForPayload projects the image count after adding a new asset and throws when it would exceed config.maxCount. This is a client-side quota enforcing a maximum number of stored image assets before persisting via persistImagePayloadAsAssetId.","triggerScenarios":"Calling persistImagePayloadAsAssetId when the store already holds maxCount images and one more would push it over; a low maxCount in config (e.g. 50) with a user bulk-importing images.","commonSituations":"Bulk uploads exceeding the configured asset limit; config regressions lowering maxCount below existing usage; long-lived local stores accumulating attachments; tests with tiny quota configs.","solutions":["Evict oldest/least-recently-used assets before inserting to stay under maxCount","Raise config.maxCount if the product limit is too low","Catch this specific error and prompt the user to delete images before adding more","Batch inserts should check remaining quota up front, not per-item"],"exampleFix":"// before\nawait persistImagePayloadAsAssetId(payload) // throws when at cap\n\n// after\nwhile (listImageAssets().length >= config.maxCount) {\n  await deleteOldestImageAsset()\n}\nawait persistImagePayloadAsAssetId(payload)","handlingStrategy":"validation","validationCode":"const count = listImageAssets().length\nif (typeof config.maxCount === 'number' && count + 1 > config.maxCount) {\n  await evictOldestImages(count + 1 - config.maxCount)\n}","typeGuard":"null","tryCatchPattern":"try { await persistImagePayloadAsAssetId(payload) } catch (e) { if (e.message.startsWith('Image storage quota exceeded: projected count')) { await evictOldestImages(1); return persistImagePayloadAsAssetId(payload) } throw e }","preventionTips":["Evict LRU assets before inserting","Check remaining quota before bulk imports","Surface quota state in the UI before users hit the cap"],"tags":["quota","storage","limit","configuration"],"backgroundTag":"storage-quota-exceeded","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}