charmbracelet/crush · error

failed to commit transaction: %w

Error message

failed to commit transaction: %w

What it means

This error wraps a failure that occurred when committing a SQLite transaction while creating a new history (prompt) file entry. The transaction started, all statements inside it succeeded, but tx.Commit() returned an error, so the whole create is rolled back and no File record is persisted. It signals a database-level problem at commit time rather than a query or argument error.

Source

Thrown at internal/history/file.go:126

		})
		if txErr != nil {
			// Rollback the transaction
			tx.Rollback()

			// Check if this is a uniqueness constraint violation
			if strings.Contains(txErr.Error(), "UNIQUE constraint failed") {
				if attempt < maxRetries-1 {
					// If we have retries left, increment version and try again
					version++
					continue
				}
			}
			return File{}, txErr
		}

		// Commit the transaction
		if txErr = tx.Commit(); txErr != nil {
			return File{}, fmt.Errorf("failed to commit transaction: %w", txErr)
		}

		file = s.fromDBItem(dbFile)
		s.Publish(pubsub.CreatedEvent, file)
		return file, nil
	}

	return file, err
}

func (s *service) Get(ctx context.Context, id string) (File, error) {
	dbFile, err := s.q.GetFile(ctx, id)
	if err != nil {
		return File{}, err
	}
	return s.fromDBItem(dbFile), nil
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check free disk space on the volume holding the SQLite database and free up space if full.
  2. Ensure no other process holds the database lock; close other instances or check the data-dir lock.
  3. Verify the database file is not corrupted by running integrity checking (PRAGMA integrity_check) and restore from backup if needed.
  4. Retry the operation once the underlying transient I/O condition is resolved; inspect the wrapped error (%w) for the concrete SQLite error code.

Example fix

// before
file, err := history.Create(ctx, sessionID, prompt)
if err != nil {
    return fmt.Errorf("create history: %w", err) // may hide disk-full
}
// after
file, err := history.Create(ctx, sessionID, prompt)
if err != nil {
    if errors.Is(err, sqlite.ErrBusy) || diskFull() {
        return fmt.Errorf("create history: storage unavailable: %w", err)
    }
    return fmt.Errorf("create history: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before creating history entries
if err := checkDiskSpace(dbDir); err != nil {
    return fmt.Errorf("insufficient storage for history db: %w", err)
}

Try / catch

file, err := history.Create(ctx, sessionID, prompt)
if err != nil {
    var sqliteErr sqlite3.Error
    if errors.As(err, &sqliteErr) {
        // inspect sqliteErr.Code (Busy, Full, Corrupt) and act
    }
    return fmt.Errorf("history create failed: %w", err)
}

Prevention

When it happens

Trigger: Calling history.Create or CreateVersion (which delegate to createWithVersion) when the underlying SQLite commit fails: disk full, database file locked by another process/connection, I/O error, or the DB connection was closed mid-transaction.

Common situations: Disk quota exhaustion on the machine holding the SQLite database; another Crush process holding the DB lock (no lock file coordination); the database file being on a full or read-only volume; a corrupted database file.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/a6d477a83448b973. Report an issue: GitHub.