{"record":{"id":"3d2e3cfd0f559509","repo":"Hmbown/CodeWhale","slug":"mcp-exceeded-its-overall-deadline","errorCode":null,"errorMessage":"MCP {} exceeded its overall {:?} deadline","messagePattern":"MCP (.+?) exceeded its overall (.+?) deadline","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mcp/src/stdio_client.rs","lineNumber":348,"sourceCode":"    fn with_limits(\n        method: &str,\n        timeout: Duration,\n        max_pages: usize,\n        max_items: usize,\n        max_bytes: usize,\n    ) -> Self {\n        Self {\n            max_pages,\n            max_items,\n            max_bytes,\n            ..Self::new(method, timeout)\n        }\n    }\n\n    fn remaining_timeout(&self) -> Result<Duration> {\n        let remaining = self.deadline.saturating_duration_since(Instant::now());\n        if remaining.is_zero() {\n            bail!(\n                \"MCP {} exceeded its overall {:?} deadline\",\n                self.method,\n                self.overall_timeout\n            );\n        }\n        Ok(remaining)\n    }\n\n    fn observe_page(&mut self, page: &Value, field: &str) -> Result<Option<String>> {\n        let values = page.get(field).and_then(Value::as_array).with_context(|| {\n            format!(\n                \"MCP {} response did not contain a '{field}' array\",\n                self.method\n            )\n        })?;\n\n        self.pages = self.pages.saturating_add(1);\n        self.items = self.items.saturating_add(values.len());","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/mcp/src/stdio_client.rs#L330-L366","documentation":"Catalog listing runs under an overall deadline; remaining_timeout computes how much time is left before each pagination request. If the deadline has already passed (remaining is zero), it fails loudly instead of issuing a call that would certainly be cut short.","triggerScenarios":"list_paginated calls remaining_timeout after Instant::now() has passed the deadline established at the start of the operation (overall_timeout elapsed, or consumed by prior pages/parsing).","commonSituations":"Slow or hung MCP server over stdio; too many pages/items to fit the budget timeout; overall_timeout configured too small for a large catalog.","solutions":["Increase the overall_timeout budget for this MCP server","Reduce catalog size limits (max_pages/max_items) so the deadline is not consumed","Investigate why the server is slow (blocking on startup, slow disk, network tool calls)"],"exampleFix":"// before\nMcpCatalogBudget::new(method, Duration::from_secs(5), ...)\n// after\nMcpCatalogBudget::new(method, Duration::from_secs(30), ...)","handlingStrategy":"try-catch","validationCode":"// before calling, ensure budget fits expected workload:\nlet pages_hint = 20;\nassert!(overall_timeout > Duration::from_secs(pages_hint), \"timeout too small for catalog size\");","typeGuard":null,"tryCatchPattern":"match client.list_resources_with_metadata().await {\n    Ok(entries) => use(entries),\n    Err(e) if e.to_string().contains(\"exceeded its overall\") => {\n        eprintln!(\"catalog listing timed out; raising budget or shrinking limits\");\n        // retry with a larger overall_timeout\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Size overall_timeout to expected page count x per-call latency","Keep per-call timeouts well below the overall deadline","Alert on servers that regularly approach the deadline"],"tags":["mcp","timeout","pagination"],"backgroundTag":"request-timeout","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}