{"record":{"id":"c1059dd986dbb693","repo":"zeroclaw-labs/zeroclaw","slug":"wait-capability-duration-exceeds-max-wait-ms-ms","errorCode":null,"errorMessage":"wait capability duration exceeds {MAX_WAIT_MS}ms","messagePattern":"wait capability duration exceeds (.+?)ms","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/sop/capability/builtins.rs","lineNumber":89,"sourceCode":"                    \"waited_ms\": { \"type\": \"integer\" }\n                }\n            })),\n        }\n    }\n\n    fn execute(&self, _ctx: CapabilityContext, input: Value) -> Result<CapabilityResult> {\n        let millis = input\n            .get(\"milliseconds\")\n            .and_then(Value::as_u64)\n            .or_else(|| {\n                input\n                    .get(\"seconds\")\n                    .and_then(Value::as_f64)\n                    .map(|seconds| (seconds.max(0.0) * 1000.0) as u64)\n            })\n            .unwrap_or(0);\n        if millis > MAX_WAIT_MS {\n            bail!(\"wait capability duration exceeds {MAX_WAIT_MS}ms\");\n        }\n        if millis > 0 {\n            std::thread::sleep(Duration::from_millis(millis));\n        }\n        Ok(CapabilityResult::success(json!({ \"waited_ms\": millis })))\n    }\n}\n\nstruct ApprovalWaitCapability;\n\nimpl SopCapability for ApprovalWaitCapability {\n    fn id(&self) -> &'static str {\n        \"approval.wait\"\n    }\n\n    fn describe(&self) -> CapabilityInfo {\n        let mut info = info(\n            self.id(),","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/sop/capability/builtins.rs#L71-L107","documentation":"The built-in `wait` capability sleeps for `with.seconds` (clamped at >= 0, converted to ms) and enforces MAX_WAIT_MS = 60_000. A duration above 60 seconds bails before sleeping — long waits are rejected rather than blocking a capability worker for minutes.","triggerScenarios":"A SOP step `uses: wait` with `with: { seconds: 90 }` (or a computed/negative-then-huge value) — anything where seconds * 1000 > 60000 at execute() time.","commonSituations":"Porting workflow sleeps from another system that allows minutes; polling loops authored as one long wait; dynamic seconds from context/variables exceeding the cap; unit tests with exaggerated durations.","solutions":["Lower `seconds` to 60 or less per wait step.","Split longer delays across multiple steps or retries (e.g. a poll step that waits 30s then re-evaluates).","If you control the SOP, model long waits as a scheduled resumption / cron trigger instead of an inline sleep.","Validate authored durations at lint time so this fails at authoring, not runtime."],"exampleFix":"# before\n- uses: wait\n  with:\n    seconds: 300\n\n# after\n- uses: wait\n  with:\n    seconds: 60","handlingStrategy":"validation","validationCode":"const MAX_WAIT_SECONDS: f64 = 60.0;\nfn wait_ok(seconds: f64) -> bool {\n    seconds.clamp(0.0, f64::MAX) * 1000.0 <= MAX_WAIT_SECONDS * 1000.0\n}\nassert!(wait_ok(step_with[\"seconds\"].as_f64().unwrap_or(0.0)));","typeGuard":"fn is_wait_within_limit(with: &serde_json::Value) -> bool {\n    with.get(\"seconds\")\n        .and_then(serde_json::Value::as_f64)\n        .map(|s| s.max(0.0) * 1000.0 <= 60_000.0)\n        .unwrap_or(true)\n}","tryCatchPattern":"match capability_registry.execute(\"wait\", &with).await {\n    Err(e) if e.to_string().contains(\"exceeds 60000ms\") => {\n        eprintln!(\"split the wait into steps of <= 60s each\");\n    }\n    rest => rest?,\n}","preventionTips":["Lint authored SOPs: reject wait steps with seconds > 60 at authoring time, not runtime.","Model long delays as scheduled resumption/cron triggers instead of inline sleeps.","Cap any dynamic seconds value from context variables before it reaches the capability."],"tags":["sop","capability","wait","timeout","limit","validation"],"backgroundTag":"value-exceeds-limit","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}