gastownhall/beads · error
compact step %q: %w
Error message
compact step %q: %w
What it means
Compact's internal execSQL helper wraps every step (branch creation, checkout, reset, squashed commit, cherry-picks, resets) as 'compact step "<step name>": %w', pinpointing which stage of the squash recipe failed. The wrapper is generic — the underlying driver error and step name together identify the cause. A deferred best-effort cleanup removes the compact-tmp branch if a later step fails after branch creation.
Source
Thrown at internal/storage/versioncontrolops/compact.go:39
//
// conn must be a single database connection (not a pooled *sql.DB) since the
// stored procedures rely on session-scoped state (current branch, working set).
func Compact(ctx context.Context, conn DBConn, initialHash, boundaryHash string, oldCommits int, recentHashes []string) (retErr error) {
branchCreated := false
// Best-effort cleanup: if any step fails after creating the temp branch,
// try to return to main and delete the temp branch so future compactions
// aren't blocked by a leftover branch.
defer func() {
if retErr != nil && branchCreated {
_, _ = conn.ExecContext(ctx, "CALL DOLT_CHECKOUT('main')")
_, _ = conn.ExecContext(ctx, "CALL DOLT_BRANCH('-D', 'compact-tmp')")
}
}()
execSQL := func(name, query string, args ...interface{}) error {
if _, err := conn.ExecContext(ctx, query, args...); err != nil {
return fmt.Errorf("compact step %q: %w", name, err)
}
return nil
}
if err := execSQL("create temp branch", "CALL DOLT_BRANCH('compact-tmp', ?)", boundaryHash); err != nil {
return err
}
branchCreated = true
if err := execSQL("checkout temp", "CALL DOLT_CHECKOUT('compact-tmp')"); err != nil {
return err
}
if err := execSQL("soft reset to initial", "CALL DOLT_RESET('--soft', ?)", initialHash); err != nil {
return err
}
msg := fmt.Sprintf("compact: squash %d commits into base snapshot", oldCommits)
if err := execSQL("commit squashed base", "CALL DOLT_COMMIT('-Am', ?)", msg); err != nil {
return errView on GitHub (pinned to 71377f2769)
Solutions
- Read the quoted step name in the error and address that specific step (e.g. 'create temp branch' → leftover compact-tmp; 'cherry-pick <hash>' → conflict)
- Delete any leftover 'compact-tmp' branch and checkout main before retrying Compact
- Verify initialHash/boundaryHash/recentHashes are valid commit hashes (dolt log)
- Run Compact on a single dedicated connection (not pooled *sql.DB) since steps depend on session state
- Inspect the wrapped driver error for conflict details and resolve before cherry-picks
Example fix
// before
_, err := db.ExecContext(ctx, "CALL DOLT_BRANCH('-D', 'compact-tmp')") // only on failure path
err := versioncontrolops.Compact(ctx, conn, init, boundary, n, hashes)
// after
// idempotent pre-cleanup before retrying
_, _ = conn.ExecContext(ctx, "CALL DOLT_CHECKOUT('main')")
_, _ = conn.ExecContext(ctx, "CALL DOLT_BRANCH('-D', 'compact-tmp')")
err := versioncontrolops.Compact(ctx, conn, init, boundary, n, hashes) Defensive patterns
Strategy: try-catch
Validate before calling
var tmp int
_ = conn.QueryRowContext(ctx,
"SELECT COUNT(*) FROM dolt_branches WHERE name = 'compact-tmp'").Scan(&tmp)
if tmp > 0 {
_, _ = conn.ExecContext(ctx, "CALL DOLT_CHECKOUT('main')")
_, _ = conn.ExecContext(ctx, "CALL DOLT_BRANCH('-D', 'compact-tmp')")
}
// also verify boundaryHash exists in dolt_log before Compact Try / catch
err := versioncontrolops.Compact(ctx, conn, init, boundary, n, hashes)
if err != nil {
var stepName string
if m := regexp.MustCompile(`compact step "([^"]+)"`).FindStringSubmatch(err.Error()); m != nil {
stepName = m[1] // route to step-specific recovery (e.g. recreate temp branch, resolve cherry-pick conflict)
}
cleanupTempBranch(ctx, conn)
return fmt.Errorf("compact failed at step %q: %w", stepName, err)
} Prevention
- Clean up leftover 'compact-tmp' branches before running Compact
- Run Compact on a single dedicated connection (session state matters)
- Validate that initial/boundary/recent hashes exist in the log
- Run PruneRemoteRefs and DoltGC after Compact as documented
- Avoid concurrent sessions mutating history during compaction
When it happens
Trigger: Calling versioncontrolops.Compact when any step fails: creating 'compact-tmp' when it already exists (leftover from a prior crash), cherry-picking a commit that conflicts or is empty without --allow-empty, DOLT_RESET on a bad hash, or connection loss mid-recipe.
Common situations: A previous failed Compact left the compact-tmp branch behind; cherry-picking recent commits whose changes conflict with the squashed base; corrupt/invalid initialHash or boundaryHash; session contention because Compact requires a dedicated single connection, not a pool.
Related errors
- failed to get issue history: %w
- failed to scan history: %w
- failed to get issue history: %w
- find initial commit: %w
- flatten step %q: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2b8833a8dd5d6aab.
Report an issue: GitHub.