tinyhumansai/openhuman · error · SubmitError

writing pool job request

Error message

writing pool job request

What it means

Writing the serialized job line to the worker subprocess's stdin failed. The comment is explicit: a write failure means the bytes never reached the worker (e.g. a reused idle worker whose process died), and it is a SubmitError::pre — the job was not accepted, so retrying on a fresh worker is safe.

Source

Thrown at src/openhuman/runtime/pool/worker.rs:230

    /// Submit one job and await its response.
    ///
    /// `hard_timeout` is a **safety net** above the worker's own soft deadline:
    /// the worker aborts a job at `req.timeout_ms` and still replies, so this
    /// only fires if the worker itself has wedged. On `Err` the caller must
    /// discard this worker — its stdio framing can no longer be trusted.
    pub async fn submit(
        &mut self,
        req: &PoolJobRequest,
        hard_timeout: Option<Duration>,
    ) -> std::result::Result<PoolJobResponse, SubmitError> {
        let mut line = serde_json::to_string(req)
            .map_err(|e| SubmitError::pre(anyhow::Error::new(e).context("serialising pool job")))?;
        line.push('\n');
        // A write failure means the bytes never reached the worker (e.g. a
        // reused idle worker died) → the job did not run → safe to retry.
        self.stdin.write_all(line.as_bytes()).await.map_err(|e| {
            SubmitError::pre(anyhow::Error::new(e).context("writing pool job request"))
        })?;
        // Past this point the request bytes are in the pipe: the job may execute,
        // so any later failure is terminal (never re-run the same job).
        self.stdin.flush().await.map_err(|e| {
            SubmitError::post(anyhow::Error::new(e).context("flushing pool job request"))
        })?;

        // Fixed deadline: `continue`ing over unparseable / mismatched-id lines
        // must NOT reset the wedged-worker timeout, so it bounds the total wait.
        let deadline = hard_timeout.map(|t| tokio::time::Instant::now() + t);
        loop {
            let next = match deadline {
                Some(dl) => match tokio::time::timeout_at(dl, self.responses.next_line()).await {
                    Ok(inner) => inner,
                    Err(_) => {
                        return Err(SubmitError::post(anyhow::anyhow!(
                            "pool worker job timed out (hard deadline; worker wedged)"
                        )))

View on GitHub (pinned to 7491200858)

Solutions

  1. Discard this worker and resubmit the job to a newly spawned worker from the pool
  2. Check why the worker process exited (OOM, crash, sandbox kill) via worker logs
  3. Cap idle-worker reuse time so dead workers are evicted before being handed jobs
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at src/openhuman/runtime/pool/worker.rs:230 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/12fd06db11ec3ff0. Report an issue: GitHub.