Skip to content

[BUG] Queue: Queue::send default content_type changed v8json (0.7 → 0.8) — silent cross-version message drops #1012

Description

@Ujang360

Is there an existing issue for this?

  • I have searched the existing issues

What version of workers-rs are you using?

0.8.4

What version of wrangler are you using?

4.100.0

Describe the bug

Summary

In worker 0.8.x, Queue::send defaults outgoing messages to content_type = Json. A consumer written against the 0.7.x default (which delivered a structured-clone object body) silently drops these messages: send() returns Ok, the consumer batch returns Ok, no exception, no log, zero messages processed. During a gradual upgrade — or when one queue is shared by services on different worker versions — this breaks invisibly.

Environment

  • worker 0.8.4 producer interoperating with a 0.7.x consumer over a Cloudflare Queue.
  • wasm32-unknown-unknown, Rust 1.96, worker-build 0.8.4.

Where it comes from

impl<T: Serialize> From<T> for SendMessage<T> hard-codes the default:

// worker-0.8.4/src/queue.rs
impl<T: Serialize> From<T> for SendMessage<T> {
    fn from(message: T) -> Self {
        Self { message, options: Some(QueueSendOptions {
            content_type: Some(QueueContentType::Json), // <-- default (was v8 in 0.7.x)
            delay_seconds: None,
        })}
    }
}

A consumer expecting the old structured-clone object typically does:

let body = raw_message.body();      // JsValue
if !body.is_object() { continue; }  // a `json`-typed body fails this → SILENTLY skipped

Why this was painful

The wire format changed across a minor-version bump with no error and no obvious note. It took a long debugging session to find, because every layer reports success.

Asks

  • Call out the default-content_type change prominently in the CHANGELOG / a 0.7→0.8 migration note — it's a wire-format behavior change, not just an API change.
  • Consider keeping the prior default, or at least making the default a clearly-documented, pinnable constant, with a note that producer and consumer must agree on content_type.
  • Optionally: give consumers a way to detect a content_type their decoder didn't expect, instead of silently yielding a non-object body.

Steps To Reproduce

  1. Producer (0.8.x): queue.send(MyMsg { .. }).await? — default content_type = Json.
  2. Consumer (0.7.x, or anything expecting a structured-clone object): if !body.is_object() { continue }.
  3. Observe: producer Ok, consumer Ok, 0 messages processed, no error anywhere.

Workaround (producer side):

queue.send(MessageBuilder::new(msg).content_type(QueueContentType::V8).build()).await?;

Related to #1013

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions