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

  1. Read the status and body in the error to identify the cause (401/403 -> fix auth, 404 -> fix url, 400 -> fix payload format)
  2. Verify the `url` option/column points to the correct endpoint path
  3. Check credentials/API keys required by the remote endpoint and any configured headers
  4. Retry after the remote service recovers (5xx/429 are transient)
  5. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/e01367aa8e3e7400. Report an issue: GitHub.