linshenkx/prompt-optimizer · error · StorageError
Database transaction error for key ${key}: ${error.message}.
Error message
Database transaction error for key ${key}: ${error.message}. Please try again. What it means
Specialized StorageError from _performAtomicUpdate when Dexie raises a PrematureCommitError — Dexie's error for code that 'commits' a transaction by doing non-transactional or async-incompatible operations inside it. The message embeds the key and the original error and asks the user to retry.
Source
Thrown at packages/core/src/services/storage/dexieStorageProvider.ts:308
// 写入新值
await tx.table('storage').put({
key,
value: JSON.stringify(newValue),
timestamp: Date.now()
});
} catch (innerError) {
// 事务内部错误,让事务回滚
console.error(`Transaction operation failed (${key}):`, innerError);
throw innerError;
}
});
} catch (error) {
console.error(`Atomic update failed (${key}):`, error);
// 如果是Dexie事务错误,提供更详细的错误信息
if (this.isError(error) && error.name === 'PrematureCommitError') {
throw new StorageError(
`Database transaction error for key ${key}: ${error.message}. Please try again.`,
'write',
);
}
throw new StorageError(`Failed to perform atomic update: ${key}`, 'write');
}
}
/**
* 批量更新操作
*/
async batchUpdate(operations: Array<{
key: string;
operation: 'set' | 'remove';
value?: string;
}>): Promise<void> {
await this.initialize();View on GitHub (pinned to 3e677b1d9f)
Solutions
- Make the update callback synchronous with respect to non-Dexie async work: compute values outside, only do Dexie ops inside
- Pre-fetch anything async before calling update() and pass results in via closure
- Retry the operation once on this specific message, since PrematureCommitError is often transient under contention
Example fix
// before
await provider.update('k', async (old) => {
const extra = await fetch('/api/x').then(r => r.json()); // kills the transaction
return merge(old, extra);
});
// after
const extra = await fetch('/api/x').then(r => r.json());
await provider.update('k', (old) => merge(old, extra)); Defensive patterns
Strategy: retry
Validate before calling
// Do all non-Dexie async work BEFORE the atomic update const external = await loadExternalData(); await provider.update(key, (old) => merge(old, external)); // callback stays Dexie-only/sync
Type guard
const isPrematureCommit = (e: unknown): e is StorageError => e instanceof StorageError && /PrematureCommit|transaction error/i.test(String((e as Error).message));
Try / catch
try { await provider.update(key, fn); } catch (e) { if (isPrematureCommit(e)) { await sleep(100); return provider.update(key, fn); } throw e; } Prevention
- Never await non-Dexie promises inside the update() callback
- Read/write only via the same Dexie instance inside transactions
- Refactor update callbacks to pure synchronous transforms over pre-fetched data
When it happens
Trigger: The update function passed to update() performs operations Dexie cannot include in the transaction: awaiting non-Dexie promises, calling other async APIs, or opening new transactions inside the callback, triggering PrematureCommitError inside db.transaction().
Common situations: Calling external APIs, timers, or other storage backends inside the atomic update callback; upgrading Dexie versions where transaction semantics tightened; doing IDB events (onsuccess handlers) manually inside the transaction.
Related errors
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/b2932b87cb634ba5.
Report an issue: GitHub.