{"record":{"id":"5095b9133e4bee15","repo":"linshenkx/prompt-optimizer","slug":"failed-to-perform-simple-update-key","errorCode":null,"errorMessage":"Failed to perform simple update: ${key}","messagePattern":"Failed to perform simple update: (.+?)","errorType":"exception","errorClass":"StorageError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/storage/dexieStorageProvider.ts","lineNumber":267,"sourceCode":"    try {\n      // 读取当前值\n      const currentRecord = await this.db.storage.get(key);\n      const currentValue = currentRecord?.value\n        ? JSON.parse(currentRecord.value) as T\n        : null;\n\n      // 应用更新函数\n      const newValue = updateFn(currentValue);\n\n      // 直接写入新值（不使用事务）\n      await this.db.storage.put({\n        key,\n        value: JSON.stringify(newValue),\n        timestamp: Date.now()\n      });\n    } catch (error) {\n      console.error(`Simple update failed (${key}):`, error);\n      throw new StorageError(`Failed to perform simple update: ${key}`, 'write');\n    }\n  }\n\n  /**\n   * 执行原子更新\n   */\n  private async _performAtomicUpdate<T>(\n    key: string,\n    updateFn: (currentValue: T | null) => T\n  ): Promise<void> {\n    try {\n      // 使用更安全的事务处理方式\n      await this.db.transaction('rw', this.db.storage, async (tx) => {\n        try {\n          // 读取当前值\n          const currentRecord = await tx.table('storage').get(key);\n          const currentValue = currentRecord?.value\n            ? JSON.parse(currentRecord.value) as T","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/storage/dexieStorageProvider.ts#L249-L285","documentation":"StorageError with code 'write' thrown by _performSimpleUpdate — the non-transactional fallback path used when the atomic/transactional update fails. It means even the plain put() of the newly computed value rejected, so both the transactional and degraded write paths failed.","triggerScenarios":"update() degrades to _performSimpleUpdate (e.g., after PrematureCommitError or unsupported transaction) and the subsequent db.storage.put of the serialized value rejects — quota exceeded, DB closed, or non-serializable state.","commonSituations":"Quota exhaustion while persisting frequently-updated keys; DB closed mid-operation during shutdown; schema drift after app upgrade.","solutions":["Inspect the logged 'Simple update failed (key):' line for the root cause","If quota: evict data or reduce write size/frequency","Ensure the database is open and the schema includes the key's table before issuing updates"],"exampleFix":"// before\nawait provider.update(key, fn);\n\n// after\ntry { await provider.update(key, fn); }\ncatch (e) {\n  if (e instanceof StorageError && e.message.includes('simple update')) {\n    await freeSpace(); await provider.update(key, fn); // retry after eviction\n  } else throw e;\n}","handlingStrategy":"fallback","validationCode":"const size = new Blob([JSON.stringify(value)]).size; if (size > 2_000_000) await trimBeforeWrite(key);","typeGuard":"const isSimpleUpdateError = (e: unknown): e is StorageError =>\n  e instanceof StorageError && /simple update/i.test(String((e as Error).message));","tryCatchPattern":"try { await provider.update(key, fn); } catch (e) { if (isSimpleUpdateError(e)) { await freeSpace(); const cur = JSON.parse((await provider.getItem(key)) ?? 'null'); await provider.setItem(key, fn(cur)); } else throw e; }","preventionTips":["Monitor quota and evict before writes fail","Ensure db is open before updates; avoid update() during shutdown","Watch the 'Simple update failed (key)' console line for the root cause"],"tags":["storage","dexie","fallback","write"],"backgroundTag":"storage-write-failed","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}