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

  1. Pass a positive byte budget, e.g. ccr.OpenWithBudget(path, 64*1024*1024).
  2. If you want the default budget, call ccr.Open(path) instead of OpenWithBudget.
  3. Audit where the budget value is computed/loaded; ensure the config field is populated with a positive number before constructing the store.
  4. If -1 or 0 means 'unlimited' in your config layer, translate it to a large positive value before calling the API.
  5. 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

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


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)