{"record":{"id":"3355f5709bb400ba","repo":"JuliusBrussee/caveman","slug":"budget-d-is-below-ccr-storage-minimum-d","errorCode":null,"errorMessage":"budget %d is below CCR storage minimum %d","messagePattern":"budget (.+?) is below CCR storage minimum (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_sqlite.go","lineNumber":386,"sourceCode":"\t\treturn err\n\t}\n\tif !os.SameFile(info, secured) {\n\t\treturn fmt.Errorf(\"file changed while securing\")\n\t}\n\treturn nil\n}\n\nfunc configureStorageBudget(db *sql.DB, maxBytes int64) error {\n\tvar pageSize int64\n\tif err := db.QueryRow(`PRAGMA page_size`).Scan(&pageSize); err != nil {\n\t\treturn fmt.Errorf(\"read page size: %w\", err)\n\t}\n\tif pageSize <= 0 {\n\t\treturn errors.New(\"invalid sqlite page size\")\n\t}\n\tmaxPages := maxBytes / pageSize\n\tif maxPages < minimumStoragePages {\n\t\treturn fmt.Errorf(\"budget %d is below CCR storage minimum %d\", maxBytes, minimumStoragePages*pageSize)\n\t}\n\tvar applied int64\n\tif err := db.QueryRow(fmt.Sprintf(`PRAGMA max_page_count=%d`, maxPages)).Scan(&applied); err != nil {\n\t\treturn err\n\t}\n\tif applied < maxPages {\n\t\tmaxPages = applied\n\t}\n\tautoCheckpoint := maxPages / 16\n\tif autoCheckpoint < 1 {\n\t\tautoCheckpoint = 1\n\t}\n\tif _, err := db.Exec(fmt.Sprintf(`PRAGMA wal_autocheckpoint=%d`, autoCheckpoint)); err != nil {\n\t\treturn err\n\t}\n\t_, err := db.Exec(fmt.Sprintf(`PRAGMA journal_size_limit=%d`, maxBytes/8))\n\treturn err\n}","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_sqlite.go#L368-L404","documentation":"configureStorageBudget enforces a CCR storage budget via SQLite PRAGMA max_page_count. This error is returned when the requested budget in bytes, divided by the database page size, yields fewer pages than minimumStoragePages (16), meaning the configured maxBytes is too small to be usable for the store.","triggerScenarios":"Calling Open/openWithBudgetHooks with a very small maxBytes (less than 16 * page_size, typically 16*4096 = 64KB); a config file supplying e.g. maxStorageBytes: 1024; a miscomputed budget from environment variables or a downsized deployment config.","commonSituations":"Operator typo setting the budget in KB while the code expects bytes; aggressive disk-quota configuration for small containers; unit mismatch after migrating config from another tool.","solutions":["Increase the configured storage budget to at least 16 pages (check PRAGMA page_size of the db; commonly >= 65536 bytes)","Check the config/env value supplying maxBytes for unit mistakes (KB vs bytes)","Let the library choose a default budget instead of passing an explicit tiny one","Verify the actual minimum via the error message: minimumStoragePages*pageSize"],"exampleFix":"// before\nstore, err := ccr.Open(dbPath, ccr.WithMaxStorageBytes(1024)) // below minimum\n// after\nstore, err := ccr.Open(dbPath, ccr.WithMaxStorageBytes(1<<20)) // 1 MiB","handlingStrategy":"validation","validationCode":"const minBytes = 16 * 4096 // minimumStoragePages * page_size\nfunc budgetOK(maxBytes int64) bool { return maxBytes >= minBytes }","typeGuard":null,"tryCatchPattern":"if err := configureBudget(db, maxBytes); err != nil && strings.Contains(err.Error(), \"below CCR storage minimum\") {\n    return fmt.Errorf(\"raise maxBytes to at least 16 pages: %w\", err)\n}","preventionTips":["Clamp configured budgets to a sane minimum (e.g. 1 MiB) before passing to Open","Watch for KB/MB vs bytes unit mistakes in config","Compute budgets from measured record sizes, not guesses"],"tags":["go","sqlite","configuration","budget"],"backgroundTag":"invalid-config-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"}