JuliusBrussee/caveman · error
ccr storage budget is below minimum
Error message
ccr storage budget %d is below minimum %d
What it means
SQLite pages are at least 512 bytes, and CCR requires a minimum page count (minimumStoragePages). openWithBudgetHooks rejects budgets below minimumStoragePages*512 before preparing files or opening a connection, because such a budget can never satisfy the minimum page requirement. The actual (possibly larger) page size is verified later by configureStorageBudget.
Solutions
- Raise the budget to at least minimumStoragePages*512 bytes; in practice use a realistic value such as several megabytes (e.g. 16*1024*1024).
- Read the minimum from the package if exported, or size the budget at the default (use ccr.Open) for tests.
- Check the unit: if your config is in KB/MB, multiply to bytes before calling OpenWithBudget.
- If the budget is proportional to a quota, clamp it with Math.Max against the library minimum before opening.
- For genuinely constrained environments, use :memory: (no budget floor needed) rather than a too-small disk budget.
Example fix
// before ccr.OpenWithBudget(path, 1024) // below minimum pages // after ccr.OpenWithBudget(path, 16*1024*1024)
Defensive patterns
Strategy: validation
Validate before calling
if maxBytes < 4096 { // conservative floor; use exported minimum when available
return fmt.Errorf("budget %d below sqlite minimum pages", maxBytes)
}
ccr.OpenWithBudget(path, maxBytes) Prevention
- Use realistic multi-megabyte budgets even in tests
- Watch for KB/MB-to-bytes unit conversion mistakes in config
- Clamp computed/proportional budgets to the library minimum
- Prefer ccr.Open (default budget) or :memory: for constrained cases
When it happens
Trigger: OpenWithBudget is called with maxBytes in (0, minimumStoragePages*512) — e.g. budgets like 1024 or 4096 bytes that are positive but too small for the required number of minimum-size SQLite pages.
Common situations: A developer picks a tiny budget for unit tests ('1KB should be enough'); a config typo like 500 instead of 500000; a size unit misread as KB instead of bytes (5 * 1024 for '5KB' intended as 5MB); a proportional budget computed from a small quota.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- budget is below CCR storage minimum
- cave_ccr_budget_exceeded
- ccr max storage bytes must be positive
- cave_breaker_retry_requires_budget
- cave_budget_denomination_ambiguous
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/c59643c77d754309.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/store_sqlite.go:170
// never evicted because an emitted transformed request may still reference any
// handle.
func OpenWithBudget(path string, maxBytes int64) (*Store, error) {
return openWithBudget(path, maxBytes, nil)
}
func openWithBudget(path string, maxBytes int64, afterPrepare func()) (*Store, error) {
return openWithBudgetHooks(path, maxBytes, afterPrepare, nil)
}
func openWithBudgetHooks(path string, maxBytes int64, afterPrepare, afterOpen func()) (*Store, error) {
if maxBytes <= 0 {
return nil, fmt.Errorf("ccr max storage bytes must be positive")
}
// SQLite pages are at least 512 bytes. Reject budgets that cannot satisfy
// CCR's minimum page count before preparing files or opening a connection.
// The actual database page size is checked by configureStorageBudget.
if maxBytes < minimumStoragePages*512 {
return nil, fmt.Errorf("ccr storage budget %d is below minimum %d", maxBytes, minimumStoragePages*512)
}
canonicalPath, err := PrepareSQLitePathCanonical(path)
if err != nil {
return nil, err
}
if afterPrepare != nil {
afterPrepare()
}
before, err := inspectSQLiteGeneration(canonicalPath)
if err != nil {
return nil, err
}
dsn := SQLiteDSN(canonicalPath)
if canonicalPath != ":memory:" {
// PrepareSQLitePathCanonical already created the file. Never recreate
// it if it vanishes between preparation and the driver's open.
dsn += "&mode=rw"
}View on GitHub (pinned to 3ee70a1026)