A consuming API has to decide what happens to the value when it fails. String::from_utf8 takes the Vec<u8> by value, and on failure the error owns it.

fn main() {
    let bytes = vec![b'o', b'k', 0xff, b'!'];
    match String::from_utf8(bytes) {
        Ok(s) => println!("{s}"),
        Err(e) => {
            let at = e.utf8_error().valid_up_to();
            let bytes = e.into_bytes();
            println!("bad byte at {at}, {} bytes back", bytes.len());
        }
    }
}

That prints bad byte at 2, 4 bytes back. No copy, and the caller gets its buffer and the offset in one value. mpsc::Sender::send does the same, SendError carries the message that could not be delivered.

The alternative is an error that only describes the failure, and then the value is dropped inside the call. For a small value that's fine. For a large buffer the caller either clones before every attempt or loses the data on the failure path, and neither shows up in the signature.

Which other std APIs consume a value and drop it on error? A short list would help me check my own interfaces against it.