gastownhall/beads · error
create checked close savepoint: %w
Error message
create checked close savepoint: %w
What it means
Beads throws this when issuing 'SAVEPOINT <name>' fails during a checked close. CloseIssueCheckedInTx creates a savepoint so it can trial-run the close policy and roll back if children are still open. The savepoint name is internally generated (fixed prefix + atomic counter), so this error almost always reflects a database/engine limitation rather than bad input.
Source
Thrown at internal/storage/issueops/close.go:237
AND child.status != 'closed'
AND NOT EXISTS (
SELECT 1 FROM dependencies AS durable WHERE durable.id = dependency.id
)
`, targetColumn)
if err := tx.QueryRowContext(ctx, wispQuery, id).Scan(&wispCount); err != nil {
if optionalBlockedTable("wisp_dependencies") && isTableNotExistError(err) {
return durableCount, nil
}
return 0, fmt.Errorf("count open wisp children for %s: %w", id, err)
}
return durableCount + wispCount, nil
}
func createCloseCheckedSavepoint(ctx context.Context, tx DBTX) (string, error) {
name := closeCheckedSavepointPrefix + strconv.FormatUint(closeCheckedSavepointCounter.Add(1), 10)
//nolint:gosec // G201: name is a fixed identifier-safe prefix plus an atomic decimal counter.
if _, err := tx.ExecContext(ctx, "SAVEPOINT "+name); err != nil {
return "", fmt.Errorf("create checked close savepoint: %w", err)
}
return name, nil
}
func rollbackAndReleaseCloseCheckedSavepoint(ctx context.Context, tx DBTX, name string) error {
rollbackErr := rollbackToCloseCheckedSavepoint(ctx, tx, name)
releaseErr := releaseCloseCheckedSavepoint(ctx, tx, name)
return errors.Join(rollbackErr, releaseErr)
}
func rollbackToCloseCheckedSavepoint(ctx context.Context, tx DBTX, name string) error {
//nolint:gosec // G201: name is generated by createCloseCheckedSavepoint.
if _, err := tx.ExecContext(ctx, "ROLLBACK TO SAVEPOINT "+name); err != nil {
return fmt.Errorf("rollback checked close savepoint: %w", err)
}
return nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Verify the storage backend and driver support SAVEPOINT inside a transaction (Dolt/MySQL do; ensure driver version is current)
- Confirm the tx passed in is a live transaction — savepoints require an active transaction context
- Upgrade the beads storage driver / Dolt if the error indicates unsupported statement syntax
- Check connection health; reconnect and retry the close if the connection dropped
Defensive patterns
Strategy: fallback
Validate before calling
// Probe savepoint support before relying on checked close
if _, err := tx.ExecContext(ctx, "SAVEPOINT probe_beads_support"); err != nil {
return fmt.Errorf("backend lacks SAVEPOINT support: %w", err)
}
_, _ = tx.ExecContext(ctx, "ROLLBACK TO SAVEPOINT probe_beads_support")
_, _ = tx.ExecContext(ctx, "RELEASE SAVEPOINT probe_beads_support") Try / catch
name, err := createCloseCheckedSavepoint(ctx, tx)
if err != nil {
if dberrors.IsConnectionError(err) {
return retryClose(ctx, id)
}
// Fallback: use plain (unchecked) close if the backend cannot savepoint
log.Printf("savepoint unavailable (%v); falling back to unchecked close", err)
return closeUnchecked(ctx, tx, id)
} Prevention
- Use a backend/driver with MySQL-style SAVEPOINT inside transactions (current Dolt or MySQL)
- Never share/pass transactions across subsystems that manage their own savepoints
- Keep transactions short to reduce the window for connection drops
- Upgrade drivers that historically lacked savepoint passthrough
When it happens
Trigger: Calling CloseIssue with check semantics when the underlying engine rejects SAVEPOINT: transaction not active (autocommit driver wrapper), engine without savepoint support, connection lost between BEGIN and SAVEPOINT, or too many nested savepoints.
Common situations: Using a driver/backend that doesn't support MySQL-style SAVEPOINT (some SQLite wrappers, older Dolt versions); a pooled connection whose transaction was already terminated; long transactions hitting engine savepoint-depth limits.
Related errors
- rollback checked close savepoint: %w
- release checked close savepoint: %w
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to set dolt_force_transaction_commit: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4ba5a992899d8d98.
Report an issue: GitHub.