risingwavelabs/risingwave · error · SinkError::Http
HTTP sink received non-success response: {} {}
Error message
HTTP sink received non-success response: {} {} What it means
After each HTTP request, the sink checks the response status. If the HTTP server returned a non-2xx status, the sink fails the write with this error, including the status code and the response body, so the user can diagnose why the remote endpoint rejected the request.
Source
Thrown at src/connector/src/sink/http.rs:469
continue;
};
let Some(url) = self.extract_url(&row)? else {
continue;
};
let resp = self
.client
.request(self.method.clone(), url)
.body(payload)
.send()
.await
.context("HTTP request failed")
.map_err(SinkError::Http)?;
if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
return Err(SinkError::Http(anyhow!(
"HTTP sink received non-success response: {} {}",
status,
body
)));
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use risingwave_common::types::{JsonbVal, Scalar};
use super::*;
#[test]View on GitHub (pinned to 6469eb736d)
Solutions
- Read the status and body in the error to identify the cause (401/403 -> fix auth, 404 -> fix url, 400 -> fix payload format)
- Verify the `url` option/column points to the correct endpoint path
- Check credentials/API keys required by the remote endpoint and any configured headers
- Retry after the remote service recovers (5xx/429 are transient)
- Validate payload format against the API contract (JSON vs plain text)
Example fix
// before CREATE SINK s FROM t WITH (connector='http', url='https://api.example.com/v1/wrongpath'); // after CREATE SINK s FROM t WITH (connector='http', url='https://api.example.com/v1/ingest', headers='Authorization: Bearer <token>');
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight check before configuring the sink
curl -s -o /dev/null -w '%{http_code}' -X POST "$URL" -H "$AUTH" -d '{}' # expect 2xx/4xx-with-clear-reason, not 5xx Try / catch
match res {
Err(e) if e.to_string().contains("non-success response") => {
let (status, body) = parse_status_and_body(&e);
if status.is_server_error() || status == 429 {
// retry with backoff
} else {
// fix auth/url/payload before retrying
}
}
other => other?,
} Prevention
- Test the endpoint with curl before creating the sink
- Set auth headers correctly in the sink options
- Monitor for 429/5xx and use retry/backoff semantics where available
- Keep payload format aligned with the API contract
When it happens
Trigger: The remote HTTP endpoint responds with 4xx/5xx during `write_chunk` — e.g. 400 bad payload, 401/403 auth failure, 404 wrong path, 429 rate limiting, 5xx server errors.
Common situations: Missing or expired API key on the remote service; wrong URL path; payload not matching the endpoint's expected schema; endpoint down or rate limited; proxy/firewall returning error pages.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Failed connection {:?},{:?}
- sending stream load request failed
- HTTP sink url option cannot coexist with url column
- HTTP sink url column must be varchar, got {:?}
- HTTP sink requires either url option or url column
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/e01367aa8e3e7400.
Report an issue: GitHub.