{"record":{"id":"91898b4d71779599","repo":"neondatabase/neon","slug":"duration-must-be-1-60-secs","errorCode":null,"errorMessage":"duration must be 1-60 secs","messagePattern":"duration must be 1-60 secs","errorType":"http","errorClass":"ApiError","httpStatus":400,"severity":"warning","filePath":"libs/http-utils/src/endpoint.rs","lineNumber":384,"sourceCode":"\n/// Generates CPU profiles.\npub async fn profile_cpu_handler(req: Request<Body>) -> Result<Response<Body>, ApiError> {\n    enum Format {\n        Pprof,\n        Svg,\n    }\n\n    // Parameters.\n    let format = match get_query_param(&req, \"format\")?.as_deref() {\n        None => Format::Pprof,\n        Some(\"pprof\") => Format::Pprof,\n        Some(\"svg\") => Format::Svg,\n        Some(format) => return Err(ApiError::BadRequest(anyhow!(\"invalid format {format}\"))),\n    };\n    let seconds = match parse_query_param(&req, \"seconds\")? {\n        None => 5,\n        Some(seconds @ 1..=60) => seconds,\n        Some(_) => return Err(ApiError::BadRequest(anyhow!(\"duration must be 1-60 secs\"))),\n    };\n    let frequency_hz = match parse_query_param(&req, \"frequency\")? {\n        None => 99,\n        Some(1001..) => return Err(ApiError::BadRequest(anyhow!(\"frequency must be <=1000 Hz\"))),\n        Some(frequency) => frequency,\n    };\n    let force: bool = parse_query_param(&req, \"force\")?.unwrap_or_default();\n\n    // Take the profile.\n    static PROFILE_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));\n    static PROFILE_CANCEL: Lazy<Notify> = Lazy::new(Notify::new);\n\n    let report = {\n        // Only allow one profiler at a time. If force is true, cancel a running profile (e.g. a\n        // Grafana continuous profile). We use a try_lock() loop when cancelling instead of waiting\n        // for a lock(), to avoid races where the notify isn't currently awaited.\n        let _lock = loop {\n            match PROFILE_LOCK.try_lock() {","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/http-utils/src/endpoint.rs#L366-L402","documentation":"Returned as HTTP 400 BadRequest by profile_cpu_handler in neon's http-utils when the seconds query parameter of /profile/cpu is present but outside the accepted 1..=60 range (parse failures produce a different 'cannot parse query param' error). The bounds cap how long the profiler may block the debugging endpoint; the default is 5 seconds.","triggerScenarios":"GET /profile/cpu?seconds=0, ?seconds=61, or ?seconds=120 — any integer below 1 or above 60 returns this 400.","commonSituations":"Grafana continuous-profiling scrape configured with a 30s+ interval that drifts over 60; someone requesting a long profile to capture a rare event; default 15m/interval arithmetic producing out-of-range seconds.","solutions":["Set seconds to a value between 1 and 60 inclusive, e.g. ?seconds=30","For longer coverage, take consecutive 60s profiles and merge them offline rather than one long request","Check scrape config (pyroscope/alloy scrape interval) and clamp it to <=60s for this endpoint"],"exampleFix":"# before\ncurl 'http://localhost:9898/profile/cpu?seconds=300'   # 400 duration must be 1-60 secs\n\n# after\ncurl 'http://localhost:9898/profile/cpu?seconds=60'","handlingStrategy":"validation","validationCode":"const seconds = Math.min(Math.max(Number(process.env.PROFILE_SECONDS ?? 5), 1), 60);\nawait fetch(`/profile/cpu?seconds=${seconds}`);","typeGuard":"function isValidProfileSeconds(s) { const n = Number(s); return Number.isInteger(n) && n >= 1 && n <= 60; }","tryCatchPattern":null,"preventionTips":["Clamp requested durations to 1-60 before calling the endpoint","For longer coverage, run repeated 60s profiles and merge offline","Keep pyroscope/alloy scrape intervals for this endpoint at or below 60s"],"tags":["neon","http-utils","profiling","query-param","cpu-profile"],"backgroundTag":"out-of-range-parameter","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}