linshenkx/prompt-optimizer · error · StorageError

Failed to perform simple update: ${key}

Error message

Failed to perform simple update: ${key}

What it means

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.

Source

Thrown at packages/core/src/services/storage/dexieStorageProvider.ts:267

    try {
      // 读取当前值
      const currentRecord = await this.db.storage.get(key);
      const currentValue = currentRecord?.value
        ? JSON.parse(currentRecord.value) as T
        : null;

      // 应用更新函数
      const newValue = updateFn(currentValue);

      // 直接写入新值(不使用事务)
      await this.db.storage.put({
        key,
        value: JSON.stringify(newValue),
        timestamp: Date.now()
      });
    } catch (error) {
      console.error(`Simple update failed (${key}):`, error);
      throw new StorageError(`Failed to perform simple update: ${key}`, 'write');
    }
  }

  /**
   * 执行原子更新
   */
  private async _performAtomicUpdate<T>(
    key: string,
    updateFn: (currentValue: T | null) => T
  ): Promise<void> {
    try {
      // 使用更安全的事务处理方式
      await this.db.transaction('rw', this.db.storage, async (tx) => {
        try {
          // 读取当前值
          const currentRecord = await tx.table('storage').get(key);
          const currentValue = currentRecord?.value
            ? JSON.parse(currentRecord.value) as T

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Inspect the logged 'Simple update failed (key):' line for the root cause
  2. If quota: evict data or reduce write size/frequency
  3. Ensure the database is open and the schema includes the key's table before issuing updates

Example fix

// before
await provider.update(key, fn);

// after
try { await provider.update(key, fn); }
catch (e) {
  if (e instanceof StorageError && e.message.includes('simple update')) {
    await freeSpace(); await provider.update(key, fn); // retry after eviction
  } else throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

const size = new Blob([JSON.stringify(value)]).size; if (size > 2_000_000) await trimBeforeWrite(key);

Type guard

const isSimpleUpdateError = (e: unknown): e is StorageError =>
  e instanceof StorageError && /simple update/i.test(String((e as Error).message));

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: Quota exhaustion while persisting frequently-updated keys; DB closed mid-operation during shutdown; schema drift after app upgrade.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/5095b9133e4bee15. Report an issue: GitHub.