{"record":{"id":"234600553a716d28","repo":"ruvnet/ruflo","slug":"savepoint-name-does-not-exist","errorCode":null,"errorMessage":"Savepoint '${name}' does not exist","messagePattern":"Savepoint '(.+?)' does not exist","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/integrations/ruvector/streaming.ts","lineNumber":903,"sourceCode":"\n    const escapedName = this.escapeIdentifier(name);\n    await this.client.query(`SAVEPOINT ${escapedName}`);\n    this.savepoints.add(name);\n    this.queryCount++;\n\n    this.emit('savepoint', { transactionId: this.transactionId, name });\n  }\n\n  /**\n   * Rollback to a savepoint.\n   *\n   * @param name - Savepoint name\n   */\n  async rollbackToSavepoint(name: string): Promise<void> {\n    this.ensureActive();\n\n    if (!this.savepoints.has(name)) {\n      throw new Error(`Savepoint '${name}' does not exist`);\n    }\n\n    const escapedName = this.escapeIdentifier(name);\n    await this.client.query(`ROLLBACK TO SAVEPOINT ${escapedName}`);\n    this.queryCount++;\n\n    this.emit('rollback_to_savepoint', { transactionId: this.transactionId, name });\n  }\n\n  /**\n   * Release a savepoint.\n   *\n   * @param name - Savepoint name\n   */\n  async releaseSavepoint(name: string): Promise<void> {\n    this.ensureActive();\n\n    if (!this.savepoints.has(name)) {","sourceCodeStart":885,"sourceCodeEnd":921,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/integrations/ruvector/streaming.ts#L885-L921","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","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"],"exampleFix":"// before\nawait tx.begin();\nawait tx.rollbackToSavepoint('sp1'); // throws\n\n// after\nawait tx.begin();\nawait tx.savepoint('sp1');\n// ... work ...\nawait tx.rollbackToSavepoint('sp1');","handlingStrategy":"validation","validationCode":"if (!hasSavepoint(tx, 'sp1')) {\n  await tx.savepoint('sp1');\n}\n// ... risky work ...\nawait tx.rollbackToSavepoint('sp1');","typeGuard":"type SavepointCapable = { savepoints: Map<string, unknown> };\nconst hasSavepoint = (t: SavepointCapable, name: string): boolean =>\n  t.savepoints.has(name);","tryCatchPattern":"try {\n  await tx.rollbackToSavepoint(name);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"does not exist\")) {\n    await tx.savepoint(name); // recreate and continue, or surface a logic error\n  } else {\n    throw err;\n  }\n}","preventionTips":["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"],"tags":["database","transactions","savepoints","not-found"],"backgroundTag":"savepoint-not-found","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}