windmill-labs/windmill · warning
e (Slack chat.update response body read error propagated via
Error message
e (Slack chat.update response body read error propagated via anyhow)
What it means
When Windmill updates the original Slack approval message after a form submission, it reads the Slack HTTP response body to log it. If reading that body fails (connection dropped, TLS error, timeout mid-read), the anyhow-wrapped io error is propagated with `?` and surfaces as 'e (Slack chat.update response body read error propagated via anyhow)'. The Slack update itself may have succeeded; only reading the response text failed.
Source
Thrown at backend/windmill-api/src/slack_approvals.rs:1239
let response = client
.post("https://slack.com/api/chat.update")
.bearer_auth(token) // Use the token for authentication
.header("Content-Type", "application/json")
.json(&payload)
.send()
.await
.map_err(|e| Error::from(anyhow::Error::new(e)))?;
if response.status().is_success() {
tracing::debug!("Slack message updated successfully!");
} else {
tracing::error!(
"Failed to update Slack message. Status: {}, Response: {:?}",
response.status(),
response
.text()
.await
.map_err(|e| Error::from(anyhow::Error::new(e)))?
);
}
Ok(())
}
View on GitHub (pinned to e474e8803c)
Solutions
- Retry the submission update or the Slack chat.update call; body-read failures are usually transient network issues.
- Verify outbound HTTPS connectivity and proxy configuration from the worker to slack.com (no idle-connection killing middleboxes).
- Check worker logs for the preceding status code — if Slack returned an error (e.g. 404 channel_not_found), fix the underlying Slack issue (channel ID, token scopes) so the success path is taken.
- If persistent, pin/update reqwest/TLS versions and ensure the container has CA certificates installed.
Example fix
// before
let body = response.text().await.map_err(|e| Error::from(anyhow::Error::new(e)))?;
// after
let body = response.text().await.unwrap_or_else(|e| {
tracing::warn!("failed to read Slack response body: {e}");
String::new()
}); Defensive patterns
Strategy: try-catch
Try / catch
// transient network issue — surface but don't fail the whole approval flow
match response.text().await {
Ok(body) => tracing::error!("Slack update failed. Status: {}, Body: {body}", response.status()),
Err(e) => tracing::error!("Slack update failed. Status: {}, body unreadable: {e}", response.status()),
} Prevention
- Ensure stable outbound HTTPS connectivity from workers to slack.com
- Check proxy/egress middleboxes that kill keep-alive connections
- Install up-to-date CA certificates in the worker image
- Log the HTTP status independently of body reading so root cause is visible
When it happens
Trigger: Slack's chat.update API returned a response, but `response.text().await` fails while draining the body — network interruption, Slack closing the connection early, or proxy/TLS termination mid-response — inside update_original_slack_message when the update returned a non-success status and the code logs the body.
Common situations: Flaky corporate networks or egress proxies between Windmill and slack.com; Slack API 5xx responses with truncated bodies; container/network timeouts; transient DNS or connection resets in self-hosted clusters with unstable outbound connectivity.
Related errors
- e (Slack chat.update request error propagated via anyhow)
- ApiError with mapped HTTP status message (e.g. "Not Found",
- Generic Error: status: ${errorStatus}; status text: ${errorS
- Dependency generation failed: ${queueResponse.status} ${queu
- Failed to poll dependencies job ${jobId}: ${e?.message ?? e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/c62b57c5050854c7.
Report an issue: GitHub.