{"record":{"id":"4f875957f3223e18","repo":"JuliusBrussee/caveman","slug":"ccr-max-storage-bytes-must-be-positive","errorCode":null,"errorMessage":"ccr max storage bytes must be positive","messagePattern":"ccr max storage bytes must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_sqlite.go","lineNumber":164,"sourceCode":"\t}\n\treturn OpenWithBudget(path, maxBytes)\n}\n\n// OpenWithBudget opens a persistent store with an explicit retained-payload\n// budget. New writes fail with ErrBudgetExceeded; existing recovery rows are\n// never evicted because an emitted transformed request may still reference any\n// handle.\nfunc OpenWithBudget(path string, maxBytes int64) (*Store, error) {\n\treturn openWithBudget(path, maxBytes, nil)\n}\n\nfunc openWithBudget(path string, maxBytes int64, afterPrepare func()) (*Store, error) {\n\treturn openWithBudgetHooks(path, maxBytes, afterPrepare, nil)\n}\n\nfunc openWithBudgetHooks(path string, maxBytes int64, afterPrepare, afterOpen func()) (*Store, error) {\n\tif maxBytes <= 0 {\n\t\treturn nil, fmt.Errorf(\"ccr max storage bytes must be positive\")\n\t}\n\t// SQLite pages are at least 512 bytes. Reject budgets that cannot satisfy\n\t// CCR's minimum page count before preparing files or opening a connection.\n\t// The actual database page size is checked by configureStorageBudget.\n\tif maxBytes < minimumStoragePages*512 {\n\t\treturn nil, fmt.Errorf(\"ccr storage budget %d is below minimum %d\", maxBytes, minimumStoragePages*512)\n\t}\n\tcanonicalPath, err := PrepareSQLitePathCanonical(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif afterPrepare != nil {\n\t\tafterPrepare()\n\t}\n\tbefore, err := inspectSQLiteGeneration(canonicalPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_sqlite.go#L146-L182","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nccr.OpenWithBudget(path, cfg.MaxBytes) // MaxBytes zero-value = 0\n// after\nif cfg.MaxBytes <= 0 { cfg.MaxBytes = 64 * 1024 * 1024 }\nccr.OpenWithBudget(path, cfg.MaxBytes)","handlingStrategy":"validation","validationCode":"if maxBytes <= 0 {\n    return fmt.Errorf(\"budget must be positive, got %d\", maxBytes)\n}\nccr.OpenWithBudget(path, maxBytes)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["go","config","validation","budget","argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}