{"record":{"id":"bd280294496a0754","repo":"risingwavelabs/risingwave","slug":"cpu-profiling-duration-must-be-greater-than-zero","errorCode":null,"errorMessage":"CPU profiling duration must be greater than zero","messagePattern":"CPU profiling duration must be greater than zero","errorType":"http","errorClass":"DashboardError","httpStatus":400,"severity":"warning","filePath":"src/meta/src/dashboard/mod.rs","lineNumber":570,"sourceCode":"            .get_worker_by_id(worker_id)\n            .await\n            .map_err(err)?\n            .context(\"worker node not found\")\n            .map_err(err)?;\n\n        let client = srv.monitor_clients.get(&worker_node).await.map_err(err)?;\n\n        let result = client.heap_profile(\"\".to_owned()).await.map_err(err)?;\n\n        Ok(result.into())\n    }\n\n    pub async fn cpu_profile(\n        Path((worker_id, duration_secs)): Path<(WorkerId, u64)>,\n        Extension(srv): Extension<Service>,\n    ) -> Result<Response> {\n        if duration_secs == 0 {\n            return Err(err(anyhow!(\n                \"CPU profiling duration must be greater than zero\"\n            )));\n        }\n\n        let flamegraph = if worker_id == crate::manager::META_NODE_ID {\n            srv.profile_service\n                .profiling(Request::new(ProfilingRequest {\n                    sleep_s: duration_secs,\n                }))\n                .await\n                .map_err(err)?\n                .into_inner()\n                .result\n        } else {\n            let worker_node = srv\n                .metadata_manager\n                .get_worker_by_id(worker_id)\n                .await","sourceCodeStart":552,"sourceCodeEnd":588,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/dashboard/mod.rs#L552-L588","documentation":"The dashboard `cpu_profile` handler validates that the requested profiling `duration_secs` path parameter is strictly greater than zero. A zero-second profile is meaningless (no samples could be collected), so the request is rejected before starting the profiler on the worker.","triggerScenarios":"Calling GET /api/v1/cpu_profile/{worker_id}/{duration_secs} with duration_secs=0, e.g. `curl http://localhost:5691/api/v1/cpu_profile/1/0`.","commonSituations":"Templated scripts computing a duration from an empty/unset variable so it defaults to 0; automated tooling that divides a budget into zero-second slices; hand-typed URLs testing the endpoint.","solutions":["Pass a positive duration in seconds, e.g. /api/v1/cpu_profile/1/10 for a 10-second profile.","Guard the calling script: skip the request when the computed duration is <= 0.","Check the URL path segments are in the right order — worker_id first, duration second."],"exampleFix":"// before\ncurl http://localhost:5691/api/v1/cpu_profile/1/0\n// after\ncurl http://localhost:5691/api/v1/cpu_profile/1/15","handlingStrategy":"validation","validationCode":"const duration = Number(opts.durationSecs);\nif (!Number.isInteger(duration) || duration <= 0) throw new Error('CPU profiling duration must be a positive integer of seconds');","typeGuard":"function isValidDurationSecs(n) { return Number.isInteger(n) && n > 0; }","tryCatchPattern":"try { const res = await fetch(`/api/v1/cpu_profile/${workerId}/${duration}`); if (!res.ok) throw new Error(await res.text()); } catch (e) { /* surface duration validation to the user */ }","preventionTips":["Default the profiling duration to a sane value (e.g. 10s) when unset.","Clamp or reject non-positive durations at the tooling boundary before calling the API."],"tags":["http-api","validation","profiling","risingwave"],"backgroundTag":"value-out-of-range","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}