{"record":{"id":"5e6fc4933f450a2d","repo":"affaan-m/ECC","slug":"page-size-must-be-greater-than-0","errorCode":null,"errorMessage":"page_size must be greater than 0","messagePattern":"page_size must be greater than 0","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/observability/mod.rs","lineNumber":288,"sourceCode":"    pub fn log(&self, event: &ToolCallEvent) -> Result<ToolLogEntry> {\n        let timestamp = chrono::Utc::now().to_rfc3339();\n\n        self.db.insert_tool_log(\n            &event.session_id,\n            &event.tool_name,\n            &event.input_summary,\n            &event.input_params_json,\n            &event.output_summary,\n            &event.trigger_summary,\n            event.duration_ms,\n            event.risk_score,\n            &timestamp,\n        )\n    }\n\n    pub fn query(&self, session_id: &str, page: u64, page_size: u64) -> Result<ToolLogPage> {\n        if page_size == 0 {\n            bail!(\"page_size must be greater than 0\");\n        }\n\n        self.db.query_tool_logs(session_id, page.max(1), page_size)\n    }\n}\n\npub fn log_tool_call(db: &StateStore, event: &ToolCallEvent) -> Result<ToolLogEntry> {\n    ToolLogger::new(db).log(event)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{SuggestedAction, ToolCallEvent, ToolLogger};\n    use crate::config::Config;\n    use crate::session::store::StateStore;\n    use crate::session::{Session, SessionMetrics, SessionState};\n    use std::path::PathBuf;\n","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/observability/mod.rs#L270-L306","documentation":"The observability tool-log query API validates pagination input and rejects `page_size == 0`, since a zero page size cannot return any rows and would produce an empty/meaningless page. The public `query` method bails immediately before delegating to the database layer.","triggerScenarios":"Calling `ToolLogStore::query(session_id, page, 0)`; UI or API layer computing page_size from an unset config defaulting to 0; a client sending `page_size=0` in a query parameter parsed straight into u64.","commonSituations":"Optional config `page_size` left unset and destructured with `unwrap_or(0)`; user submitting a form/page-size input with 0 or blank that parses to 0; pagination loop that decrements to 0.","solutions":["Pass a page_size >= 1, e.g. use a sensible default like 20 or 50.","Clamp the caller-supplied page size: `page_size.max(1)` before calling `query`.","Fix the config default so unset page size falls back to a positive constant instead of 0.","Note the implementation itself clamps `page` to at least 1 — only `page_size` must be sanitized by the caller."],"exampleFix":"// before\nlet page = store.query(&session_id, 1, config.page_size); // page_size defaults to 0\n// after\nlet page = store.query(&session_id, 1, config.page_size.max(1).min(100));","handlingStrategy":"validation","validationCode":"fn sanitize_page_size(raw: u64) -> u64 {\n    raw.clamp(1, 100)\n}","typeGuard":"fn is_valid_page_size(n: u64) -> bool { n > 0 }","tryCatchPattern":"match store.query(&session_id, page, page_size) {\n    Err(e) if e.to_string().contains(\"page_size must be greater than 0\") => {\n        let page = store.query(&session_id, page, DEFAULT_PAGE_SIZE)?;\n    }\n    other => other?,\n}","preventionTips":["Always default page_size to a positive constant (e.g. 50), never 0.","Clamp user-supplied pagination values at the API boundary.","Cover pagination edge cases (0, negative-in-JSON, huge) in tests.","Mirror the library's contract: page is auto-clamped, page_size is not."],"tags":["pagination","validation","observability","api"],"backgroundTag":"invalid-query-parameter","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}