JuliusBrussee/caveman · error

configure sqlite storage budget

Error message

configure sqlite storage budget %q: %w

What it means

This error wraps failure of configureStorageBudget, which applies the configured max storage size to the SQLite store (e.g. PRAGMA max_page_count or equivalent) during open. If the budget cannot be set, the store closes the db and aborts the open because an unbounded database would violate its retention guarantees.

Solutions

  1. Verify maxBytes is positive and larger than the current database size; increase it or delete/compact the db
  2. Ensure no other process holds a write lock during open
  3. Check the db file is writable (setting the budget requires a write)
  4. Unwrap the %w chain to read the underlying SQLite error for the exact cause

Example fix

// before
store, err := ccr.Open(dbPath, ccr.WithMaxBytes(1024)) // smaller than existing 5 MB db
// after
info, _ := os.Stat(dbPath)
maxBytes := int64(1024)
if info != nil && info.Size() > maxBytes {
    maxBytes = info.Size() * 2 // budget above current size
}
store, err := ccr.Open(dbPath, ccr.WithMaxBytes(maxBytes))
Defensive patterns

Strategy: validation

Validate before calling

func validateBudget(dbPath string, maxBytes int64) error {
    if maxBytes <= 0 {
        return fmt.Errorf("maxBytes must be positive")
    }
    if fi, err := os.Stat(dbPath); err == nil && fi.Size() >= maxBytes {
        return fmt.Errorf("maxBytes %d below current db size %d", maxBytes, fi.Size())
    }
    return nil
}

Prevention

When it happens

Trigger: configureStorageBudget's pragma/query fails due to lock contention, or the requested maxBytes value translates to an invalid/unsupported pragma value (e.g. budget below current file size or non-positive).

Common situations: Passing a maxBytes value smaller than the existing database; another process holding a lock; db on read-only media.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/691cd9d9eeb236ae. Report an issue: GitHub.

Appendix: source

Thrown at engine/ccr/store_sqlite.go:229

			return nil, fmt.Errorf("read sqlite journal mode: %w", err)
		}
		walJournal = strings.EqualFold(mode, "wal")
	}
	if err := RetryOnBusy(func() error { _, e := db.Exec(schema); return e }); err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, fmt.Errorf("migrate sqlite %q: %w", canonicalPath, err)
	}
	if err := RetryOnBusy(func() error { return ensureMetadataColumn(db) }); err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, fmt.Errorf("migrate sqlite metadata %q: %w", canonicalPath, err)
	}
	if err := RetryOnBusy(func() error { return ensureDataRefColumn(db) }); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("migrate sqlite data_ref %q: %w", canonicalPath, err)
	}
	if err := configureStorageBudget(db, maxBytes); err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, fmt.Errorf("configure sqlite storage budget %q: %w", canonicalPath, err)
	}
	opened, err := inspectSQLiteGeneration(canonicalPath)
	if err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, err
	}
	if !before.sameExisting(opened) || (walJournal && (opened[1] == nil || opened[2] == nil)) {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, ErrStorageChanged
	}
	// The schema/budget queries have opened the WAL. Capture the resulting
	// journals before final permission checks, so losing a newly-created
	// journal is distinguishable from normal creation during SQLite open.
	before = opened
	if afterOpen != nil {
		afterOpen()
	}
	if err := secureSQLiteFiles(canonicalPath); err != nil {

View on GitHub (pinned to 3ee70a1026)