JuliusBrussee/caveman · error
ccr max storage bytes must be positive
Error message
ccr max storage bytes must be positive
What it means
openWithBudgetHooks rejects a maxBytes budget of zero or negative before doing any filesystem work. CCR budgets bound retained payload bytes; a non-positive budget is meaningless, so OpenWithBudget fails fast with this error instead of opening a store that could never write.
Solutions
- Pass a positive byte budget, e.g. ccr.OpenWithBudget(path, 64*1024*1024).
- If you want the default budget, call ccr.Open(path) instead of OpenWithBudget.
- Audit where the budget value is computed/loaded; ensure the config field is populated with a positive number before constructing the store.
- If -1 or 0 means 'unlimited' in your config layer, translate it to a large positive value before calling the API.
- Add an up-front check in your own code that logs and rejects non-positive budgets before opening.
Example fix
// before
ccr.OpenWithBudget(path, cfg.MaxBytes) // MaxBytes zero-value = 0
// after
if cfg.MaxBytes <= 0 { cfg.MaxBytes = 64 * 1024 * 1024 }
ccr.OpenWithBudget(path, cfg.MaxBytes) Defensive patterns
Strategy: validation
Validate before calling
if maxBytes <= 0 {
return fmt.Errorf("budget must be positive, got %d", maxBytes)
}
ccr.OpenWithBudget(path, maxBytes) Prevention
- Never pass a zero-value struct field as the budget; initialize defaults
- Do not use -1/0 to mean 'unlimited' — call ccr.Open for defaults
- Log the resolved budget at startup to catch zero-defaults early
- Centralize budget construction in one validated config loader
When it happens
Trigger: OpenWithBudget / openWithBudget is called with maxBytes <= 0 — typically a computed value from config that defaulted to 0, an int64 zero-value passed by mistake, or a negative constant used to signal 'no limit' (which this API does not accept).
Common situations: A struct holding the budget was zero-initialized and never populated; config parsing left the field unset; a caller passed -1 expecting unlimited behavior; test code copied a stub with maxBytes 0.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- rewriter: theta must not be negative, got
- arm must be or
- cave_breaker_retry_requires_budget
- cave_budget_denomination_ambiguous
- cave_budget_initial_invalid
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/4f875957f3223e18.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/store_sqlite.go:164
}
return OpenWithBudget(path, maxBytes)
}
// OpenWithBudget opens a persistent store with an explicit retained-payload
// budget. New writes fail with ErrBudgetExceeded; existing recovery rows are
// 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
}View on GitHub (pinned to 3ee70a1026)