benbjohnson/litestream · error

commit transaction

Error message

commit transaction: %w

What it means

populateTable wraps a failed tx.Commit in this error. After inserting all rows of a batch the transaction is committed to make the batch durable; the WAL then grows and litestream can pick up the change. A commit failure means the entire batch is rolled back and population aborts (ctx cancellation is checked after each successful commit, not here).

Solutions

  1. Check free disk space including room for WAL growth; reduce BatchSize if transactions are too large.
  2. Inspect the wrapped SQLite error for SQLITE_FULL/SQLITE_IOERR.
  3. Verify the filesystem is writable and quotas are not exceeded.
  4. Ensure only one writer (this tool) touches the database during population.

Example fix

// before
if err := tx.Commit(); err != nil {
    return fmt.Errorf("commit transaction: %w", err)
}
// after
if err := tx.Commit(); err != nil {
    return fmt.Errorf("commit transaction (batch %d-%d): %w", i, batchEnd, err) // include batch range for diagnosis
}
Defensive patterns

Strategy: validation

Validate before calling

// ensure free space for WAL before large batch commits
var st syscall.Statfs_t
if err := syscall.Statfs(filepath.Dir(c.DB), &st); err == nil {
    avail := int64(st.Bavail) * int64(st.Bsize)
    if avail < int64(c.BatchSize*c.RowSize)*4 {
        return fmt.Errorf("low disk for WAL: %d bytes available", avail)
    }
}

Try / catch

if err := tx.Commit(); err != nil {
    if strings.Contains(err.Error(), "SQLITE_FULL") || strings.Contains(err.Error(), "SQLITE_IOERR") {
        // operational failure: free space / check fs, then retry run
        return fmt.Errorf("commit transaction (operational): %w", err)
    }
    return fmt.Errorf("commit transaction: %w", err)
}

Prevention

When it happens

Trigger: tx.Commit() fails: disk full while flushing WAL frames, I/O error on the WAL or database file, the database was locked/invalidated by another connection during the transaction, or driver connection loss.

Common situations: Large BatchSize making big transactions that exhaust free space when written to the WAL; filesystem errors (quota, read-only remount); a concurrent process forcing WAL checkpoint failures.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/523fc879589bf53e. Report an issue: GitHub.

Appendix: source

Thrown at cmd/litestream-test/populate.go:210

		}

		for j := i; j < batchEnd; j++ {
			cryptorand.Read(data)
			textField := fmt.Sprintf("row_%d_%d", i, j)
			intField := rand.Int63()
			floatField := rand.Float64() * 1000
			timestamp := time.Now().Unix()

			if _, err := stmt.Exec(data, textField, intField, floatField, timestamp); err != nil {
				stmt.Close()
				tx.Rollback()
				return fmt.Errorf("insert row: %w", err)
			}
		}

		stmt.Close()
		if err := tx.Commit(); err != nil {
			return fmt.Errorf("commit transaction: %w", err)
		}

		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}
	}

	return nil
}

func (c *PopulateCommand) Usage() {
	fmt.Fprintln(c.Main.Stdout, `
Populate a SQLite database to a target size for testing.

Usage:

View on GitHub (pinned to 4ed7a308f6)