ruvnet/ruflo · error
Savepoint '${name}' does not exist
Error message
Savepoint '${name}' does not exist What it means
Thrown by rollbackToSavepoint() when the given name is not in the wrapper's savepoints map. Savepoints must be created via savepoint(name) on the same active transaction before they can be rolled back to; the map (not the DB catalog) is the source of truth, so names created elsewhere, released already, or misspelled all fail.
Source
Thrown at v3/@claude-flow/plugins/src/integrations/ruvector/streaming.ts:903
const escapedName = this.escapeIdentifier(name);
await this.client.query(`SAVEPOINT ${escapedName}`);
this.savepoints.add(name);
this.queryCount++;
this.emit('savepoint', { transactionId: this.transactionId, name });
}
/**
* Rollback to a savepoint.
*
* @param name - Savepoint name
*/
async rollbackToSavepoint(name: string): Promise<void> {
this.ensureActive();
if (!this.savepoints.has(name)) {
throw new Error(`Savepoint '${name}' does not exist`);
}
const escapedName = this.escapeIdentifier(name);
await this.client.query(`ROLLBACK TO SAVEPOINT ${escapedName}`);
this.queryCount++;
this.emit('rollback_to_savepoint', { transactionId: this.transactionId, name });
}
/**
* Release a savepoint.
*
* @param name - Savepoint name
*/
async releaseSavepoint(name: string): Promise<void> {
this.ensureActive();
if (!this.savepoints.has(name)) {View on GitHub (pinned to fa13ee4ad6)
Solutions
- Create the savepoint first: await tx.savepoint('sp1') before any rollbackToSavepoint('sp1')
- Remember that releaseSavepoint removes the name — do not roll back to a released savepoint; re-create it if needed
- Derive names from constants or a single helper so creation and rollback sites cannot diverge
Example fix
// before
await tx.begin();
await tx.rollbackToSavepoint('sp1'); // throws
// after
await tx.begin();
await tx.savepoint('sp1');
// ... work ...
await tx.rollbackToSavepoint('sp1'); Defensive patterns
Strategy: validation
Validate before calling
if (!hasSavepoint(tx, 'sp1')) {
await tx.savepoint('sp1');
}
// ... risky work ...
await tx.rollbackToSavepoint('sp1'); Type guard
type SavepointCapable = { savepoints: Map<string, unknown> };
const hasSavepoint = (t: SavepointCapable, name: string): boolean =>
t.savepoints.has(name); Try / catch
try {
await tx.rollbackToSavepoint(name);
} catch (err) {
if (err instanceof Error && err.message.includes("does not exist")) {
await tx.savepoint(name); // recreate and continue, or surface a logic error
} else {
throw err;
}
} Prevention
- Create savepoints immediately before the work they guard; verify with a hasSavepoint helper before rollback
- Remember releaseSavepoint deletes the name — re-create before rolling back to it
- Centralize savepoint names in constants shared by create/rollback sites
When it happens
Trigger: Calling rollbackToSavepoint('sp1') without a prior savepoint('sp1'); rolling back to a savepoint after releaseSavepoint already deleted it from the map; name drift between creation ('sp_1') and rollback ('sp1').
Common situations: Nested-workflow code where the create and rollback sites are far apart or written by different authors; generated names that differ across retries; refactors that renamed savepoints on one path only.
Related errors
- File not found
- Index ${indexName} not found
- Transaction already active
- hexToBytes: odd-length hex string
- SSRF guard: only HTTPS URLs are permitted, got ${parsed.prot
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/234600553a716d28.
Report an issue: GitHub.