{"record":{"id":"3c1087b6a3b33f3b","repo":"JuliusBrussee/caveman","slug":"caveman-ccr-max-bytes-must-be-a-positive-integer","errorCode":null,"errorMessage":"CAVEMAN_CCR_MAX_BYTES must be a positive integer","messagePattern":"CAVEMAN_CCR_MAX_BYTES must be a positive integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_sqlite.go","lineNumber":143,"sourceCode":"\treturn err\n}\n\nfunc isBusy(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\ts := err.Error()\n\treturn strings.Contains(s, \"database is locked\") || strings.Contains(s, \"SQLITE_BUSY\")\n}\n\n// Open opens (creating if needed) the SQLite database at path and migrates the\n// schema. Use \":memory:\" for an ephemeral store (tests, the eval harness).\nfunc Open(path string) (*Store, error) {\n\tmaxBytes := DefaultMaxStorageBytes\n\tif raw := strings.TrimSpace(os.Getenv(\"CAVEMAN_CCR_MAX_BYTES\")); raw != \"\" {\n\t\tparsed, err := strconv.ParseInt(raw, 10, 64)\n\t\tif err != nil || parsed <= 0 {\n\t\t\treturn nil, fmt.Errorf(\"CAVEMAN_CCR_MAX_BYTES must be a positive integer\")\n\t\t}\n\t\tmaxBytes = parsed\n\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","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_sqlite.go#L125-L161","documentation":"The CAVEMAN_CCR_MAX_BYTES environment variable was set but could not be parsed as a positive 64-bit integer, or parsed to a value <= 0. Open rejects the configuration up front rather than falling back to a default, so a bad env var fails loudly instead of silently changing the budget.","triggerScenarios":"ccr.Open(path) is called with CAVEMAN_CCR_MAX_BYTES set to something like \"abc\", \"\", after TrimSpace it is non-empty but non-numeric (e.g. \"10MB\", \"1_000\"), negative (\"-5\"), or zero (\"0\"), or a value above int64 range (\"99999999999999999999\").","commonSituations":"Operator writes a human-readable size like \"100MB\" instead of raw bytes; quotes or whitespace/unit suffixes copied from docs; value 0 intended to mean 'unlimited'; CI secrets misconfigured with a placeholder string.","solutions":["Set CAVEMAN_CCR_MAX_BYTES to a plain positive integer of bytes, e.g. 104857600 for 100 MiB.","Unset the variable entirely to use DefaultMaxStorageBytes if you did not intend to override the budget.","Remove unit suffixes, underscores, thousands separators, and surrounding quotes from the value.","Convert human sizes before export: 50MB -> 52428800.","Check the deployment config/secret for placeholder values like \"<max-bytes>\" or \"changeme\"."],"exampleFix":"# before\nexport CAVEMAN_CCR_MAX_BYTES=100MB\n# after\nexport CAVEMAN_CCR_MAX_BYTES=104857600","handlingStrategy":"validation","validationCode":"raw := strings.TrimSpace(os.Getenv(\"CAVEMAN_CCR_MAX_BYTES\"))\nif raw != \"\" {\n    if n, err := strconv.ParseInt(raw, 10, 64); err != nil || n <= 0 {\n        return fmt.Errorf(\"CAVEMAN_CCR_MAX_BYTES must be a positive integer, got %q\", raw)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set the variable as plain decimal bytes, no unit suffixes","Unset the variable rather than setting 0 when you want the default","Validate deployment env/secrets at startup with a fail-fast preflight","Document accepted format (int64 > 0) next to the config key"],"tags":["go","env-var","config","validation","ccr"],"backgroundTag":"invalid-env-var-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"}