actix/actix-web · error

cannot reuse response builder

Error message

cannot reuse response builder

What it means

This is a runtime panic from the actix-http `ResponseBuilder::message_body()` method. The builder uses an `Option<BoxedResponseHead>` internally; calling `message_body()` (or `body()`, `finish()`) takes the head via `self.head.take()` at line 223, leaving it as `None`. A second call to any body-producing method finds `None` and panics via `.expect("cannot reuse response builder")`.

Solutions

  1. Call `.body()` or `.finish()` exactly once per builder instance
  2. Use `ResponseBuilder::take()` to extract the builder state into a fresh instance if you need to split the flow
  3. Return the response immediately after building it rather than reusing the builder
  4. Use `match` or `if/else` that produces a single `.body()` call at the end of the function

Example fix

// before
let mut builder = ResponseBuilder::new(StatusCode::OK);
let res1 = builder.finish();
let res2 = builder.finish(); // panics

// after
let res = ResponseBuilder::new(StatusCode::OK).finish();
Defensive patterns

Strategy: validation

Validate before calling

// Track builder usage to prevent reuse. Prefer functional construction.
// Always build in a single chain to guarantee one terminal call:
fn build_response(status: actix_http::StatusCode) -> actix_http::Response<actix_http::body::EitherBody<()>> {
    ResponseBuilder::new(status)
        .insert_header(("X-Test", "1"))
        .finish()
}

Try / catch

// Rust does not catch panics in normal code.
// Ensure .body()/.finish() is called exactly once.
// If you need conditional logic, structure it so only one terminal call runs:
let res = if condition {
    builder.body("data")
} else {
    builder.finish()
};
// Do NOT call any builder method after this point.

Prevention

When it happens

Trigger: Calling `.body(...)` or `.finish()` twice on the same `ResponseBuilder`, or calling `.body(...)` after `.finish()` (since `finish()` internally calls `body(())`). Also panics if calling any method that accesses `self.inner()` after the head has been taken.

Common situations: Storing a `ResponseBuilder` in a variable and conditionally calling `.body()` in different branches where both might execute. Most commonly happens with mutable references shared across code paths.

Related errors


AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09). Data as JSON: /api/errors/bf42cc32d0fbae98. Report an issue: GitHub.

Appendix: source

Thrown at actix-http/src/responses/builder.rs:223

    pub fn body<B>(&mut self, body: B) -> Response<EitherBody<B>>
    where
        B: MessageBody + 'static,
    {
        match self.message_body(body) {
            Ok(res) => res.map_body(|_, body| EitherBody::left(body)),
            Err(err) => Response::from(err).map_body(|_, body| EitherBody::right(body)),
        }
    }

    /// Generate response with a body.
    ///
    /// This `ResponseBuilder` will be left in a useless state.
    pub fn message_body<B>(&mut self, body: B) -> Result<Response<B>, Error> {
        if let Some(err) = self.err.take() {
            return Err(Error::new_http().with_cause(err));
        }

        let head = self.head.take().expect("cannot reuse response builder");

        Ok(Response {
            head,
            body,
            extensions: RefCell::new(Extensions::new()),
        })
    }

    /// Generate response with an empty body.
    ///
    /// This `ResponseBuilder` will be left in a useless state.
    #[inline]
    pub fn finish(&mut self) -> Response<EitherBody<()>> {
        self.body(())
    }

    /// Create an owned `ResponseBuilder`, leaving the original in a useless state.
    pub fn take(&mut self) -> ResponseBuilder {

View on GitHub (pinned to 4d435abc28)