{"record":{"id":"444dc4a60a5b7df1","repo":"xai-org/grok-build","slug":"waiting-on-command-e","errorCode":null,"errorMessage":"waiting on command: {e}","messagePattern":"waiting on command: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/auth_provider.rs","lineNumber":317,"sourceCode":"    let mut out_buf = Vec::new();\n    let mut err_buf = Vec::new();\n\n    // One extra stdout byte so an over-cap write is detectable, not truncated.\n    // The stderr read is advisory (it only feeds the failure log), so only\n    // stdout governs the mint.\n    let capture = async {\n        let (out_res, err_res) = tokio::join!(\n            read_capped(stdout, PROVIDER_STDOUT_CAP_BYTES + 1, &mut out_buf),\n            read_capped(stderr, PROVIDER_STDERR_CAP_BYTES, &mut err_buf),\n        );\n        if let Err(e) = err_res {\n            tracing::debug!(error = %e, \"auth provider: stderr capture failed (advisory)\");\n        }\n        out_res.map_err(|e| anyhow::anyhow!(\"reading command stdout: {e}\"))?;\n        child\n            .wait()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"waiting on command: {e}\"))\n    };\n\n    let status = match tokio::time::timeout(timeout, capture).await {\n        Ok(res) => res?,\n        Err(_elapsed) => {\n            let _ = group.kill();\n            anyhow::bail!(\"command timed out after {}s\", timeout.as_secs());\n        }\n    };\n    if out_buf.len() as u64 > PROVIDER_STDOUT_CAP_BYTES {\n        anyhow::bail!(\"command wrote more than {PROVIDER_STDOUT_CAP_BYTES} bytes to stdout\");\n    }\n    Ok(std::process::Output {\n        status,\n        stdout: out_buf,\n        stderr: err_buf,\n    })\n}","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/auth_provider.rs#L299-L335","documentation":"After capturing output, run_capped awaits child.wait(); an error there is wrapped as 'waiting on command'. It runs under the caller-supplied timeout; the timeout path kills the group separately.","triggerScenarios":"tokio's wait() failing to reap the child — e.g. the child was already reaped by an external SIGCHLD handler, or the process handle became invalid.","commonSituations":"Embedding the library in an app with its own SIGCHLD/sigaction handling that races tokio's reaper, or PID reuse/kill races in restricted environments.","solutions":["Remove custom SIGCHLD handlers that reap children behind tokio's back","Retry the token mint; this is often a one-off race","If embedding, let tokio own child reaping exclusively"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match mint_provider_token().await {\n    Err(e) if e.to_string().contains(\"waiting on command\") => {\n        eprintln!(\"could not reap helper process: {e}; retrying once\");\n        mint_provider_token().await?;\n    }\n    other => other?,\n}","preventionTips":["Do not install custom SIGCHLD handlers when embedding tokio apps","Let tokio exclusively own child process reaping","Surface once-only retries for wait races"],"tags":["process","async","tokio"],"backgroundTag":"child-process-wait-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}