actix/actix-web · critical
cannot reuse response builder
Error message
cannot reuse response builder
What it means
`HttpResponseBuilder` holds the in-progress response in `res: Option<...>`. Consuming methods (`body`, `message_body`, `finish`) call `.take()`, leaving `res = None`. `extensions()` at actix-web/src/response/builder.rs:269-273 reads `self.res.as_ref().expect("cannot reuse response builder")`, so calling `extensions()` after the builder was finished panics.
Source
Thrown at actix-web/src/response/builder.rs:272
/// .finish();
/// ```
#[cfg(feature = "cookies")]
pub fn cookie(&mut self, cookie: cookie::Cookie<'_>) -> &mut Self {
match cookie.to_string().try_into_value() {
Ok(hdr_val) => self.append_header((header::SET_COOKIE, hdr_val)),
Err(err) => {
self.error = Some(err.into());
self
}
}
}
/// Returns a reference to the response-local data/extensions container.
#[inline]
pub fn extensions(&self) -> Ref<'_, Extensions> {
self.res
.as_ref()
.expect("cannot reuse response builder")
.extensions()
}
/// Returns a mutable reference to the response-local data/extensions container.
#[inline]
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
self.res
.as_mut()
.expect("cannot reuse response builder")
.extensions_mut()
}
/// Set a body and build the `HttpResponse`.
///
/// Unlike [`message_body`](Self::message_body), errors are converted into error
/// responses immediately.
///
/// `HttpResponseBuilder` can not be used after this call.View on GitHub (pinned to 937960ca67)
Solutions
- Treat `finish()`/`body()`/`message_body()` as the terminal call — never use the builder afterward.
- Read `extensions()`/`extensions_mut()` before finishing the response.
- If you need extension data after building, capture it from the returned `HttpResponse` via `res.extensions()` instead of the builder.
Example fix
// before
let mut b = HttpResponse::Ok();
b.insert_header(("X", "1"));
let resp = b.finish();
let ext = b.extensions(); // panics
// after
let mut b = HttpResponse::Ok();
b.insert_header(("X", "1"));
let ext = b.extensions(); // read before finish
let resp = b.finish();
// or use resp.extensions() afterwards Defensive patterns
Strategy: validation
Validate before calling
// Treat the builder as single-use. If you must track state, wrap usage so that
// extensions()/extensions_mut() are only called before a terminal method.
// Pseudocode guard for your own helpers:
struct SafeBuilder { b: Option<HttpResponseBuilder> }
impl SafeBuilder {
fn extensions(&self) -> bool { self.b.is_some() }
fn finish(&mut self) -> HttpResponse {
self.b.take().unwrap().finish()
}
} Prevention
- Call extensions()/extensions_mut() only before finish/body/message_body.
- Read extension data from the returned HttpResponse after building.
When it happens
Trigger: Calling `.finish()` (or `.body(...)`) on a builder, then calling `.extensions()` on the same builder instance.
Common situations: Storing a builder in a variable, finishing it, and accidentally touching it again; or shared/multiple-finish code paths.
Related errors
- All default headers must be added before cloning.
- Invalid header name
- Invalid header value
- Unsupported HTTP version: {:?}.
- actix-http client only supports versions http/1.1 & http/2
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/f379a80f1bd08111.json.
Report an issue: GitHub.