Specifically, the "message" in your lambda is bound *to the variable message*, not to the value that it happens to have when you instantiate the delegate/lambda function.
If you wrap the instantiation in a local copy that has shorter scope, it will likely work. This doesn't copy the data of the message, but it binds the delegate to the variable "copy" that goes out of scope, and thus can't be re-assigned later.
Perhaps something like this:
while (whatever)
{
message = whatever();
if (message.Length > 0)
{
byte[] copy = message;
(new Thread(() => this.HandleMessage(copy))).Start();
}
}