Vercel Queues: consumer callback never invoked on Next.js 16 (monorepo)

Expected: After send('my-topic', payload) succeeds, the push-mode consumer registered via experimentalTriggers in vercel.json should be invoked by Vercel’s queue infrastructure.

Actual: send() succeeds and messages appear in the Queues dashboard (Queued count increments), but the consumer handler is never invoked:

  • console.log at the top of handleCallback never fires — zero entries in Runtime Logs over 7+ days, across Preview and Production
  • Observability → Queues shows 0 Received, 0 Deleted, no Consumer Group for every topic in this project
  • 3 different topics tried in this project — identical behavior on all three
  • A separate test project I own (flat repo, Next.js 15, same SDK usage) works end-to-end, so I don’t think handleCallback / vercel.json are wrong on my side

Consumer route (apps/client/app/api/queues/my-topic/route.ts):

import { handleCallback } from '@vercel/queue';

export const maxDuration = 60;

export const POST = handleCallback(async (message, metadata) => {
  console.log('[Queue] Processing', metadata.messageId);
  // … real work
});

Trigger config (apps/client/vercel.json):

{
  "functions": {
    "app/api/queues/my-topic/route.ts": {
      "maxDuration": 60,
      "experimentalTriggers": [{ "type": "queue/v2beta", "topic": "my-topic" }]
    }
  }
}

Producer (called from a normal route handler):

import { send } from '@vercel/queue';
const result = await send('my-topic', { hello: 'world' });
// result.messageId is a valid string — message is accepted

Steps:

  1. Deploy the above. Build succeeds. Route shows up in the build output.
  2. Hit any endpoint that calls send() — Queues dashboard shows Queued count going up.
  3. Wait any amount of time. Consumer console.log never appears. Received stays 0. No Consumer Group entry.

Things I’ve tried that did not fix it:

  • Bootstrapping a stub consumer on production first, then testing from preview
  • Creating a brand-new topic with a fresh name
  • Bumping @vercel/queue 0.1.4 → 0.1.6 (latest)
  • Disabling Deployment Protection on preview (consumer URL goes from 401 → reachable)
  • Disabling Attack Challenge Mode (was serving bot-challenge HTML to consumer URL)
  • Adding a custom Allow rule for /api/queues/*
  • Also placing vercel.json at the monorepo root with paths qualified as apps/client/app/api/queues/…
  • Framework: Next.js 16.1.4 with cacheComponents: true (experimental)
  • @vercel/queue: ^0.1.6
  • Structure: TurboRepo monorepo, Vercel Root Directory = apps/client
  • vercel.json location: apps/client/vercel.json
  • "type": "queue/v2beta" in experimentalTriggers (matches the quickstart docs)
  • Node 22.x
  • Affected topics include queues used by an existing daily cron → the cron has been firing for a week with zero consumer invocations, so it’s not a recent regression in my code — looks like it’s been like this since the Next.js 16 upgrade.

Happy to share project ID / deployment IDs over DM if someone from the Queues team can verify whether the subscriptions were actually registered for this project.

Thanks!

Thank you for bringing this to our attention. To ensure this is investigated with the necessary priority and privacy, please report all security-related concerns, potential exploits, or abuse directly to the Vercel Security Team.

Please submit your report here: Report Abuse On Vercel

Reporting via this official channel is the fastest way to reach our security engineers and ensures that sensitive information is handled in a secure environment rather than a public forum.

Sounds like an interesting issue, let me do some looking/poking around and I’ll try and figure out what’s going on!

This is going to be a bit long-winded, but hopefully it’s worth it. I’ve done a root cause analysis. Hopefully most of this is up-to-date, it’s not all info from the Vercel documentation—if not of the below helps and you have a Pro/Enterprise plan I’d recommend reaching out to Vercel support at support@vercel.com, if not I’m pretty sure you can request a support case on the Hobby plan at the help page (also accessible via Vercel Dashboard → Support → New Case).

Root Cause Analysis

Cause #1

GitHub issue #91465 documents Next.js 16 App Router API routes hanging on Vercel with 504 gateway timeouts in larger monorepos (~70+ routes). Key characteristics align precisely with reported symptoms:

  • Routes work locally but fail on Vercel deployment
  • Zero runtime logs—serverless function code never executes
  • Even zero-import routes (e.g., /api/ping) hang indefinitely
  • Affects both Turbopack and webpack builds
  • Pages (SSR) work; only API routes fail

Technical mechanism: The hang appears during serverless function initialization phase (shared chunks or runtime bootstrap) rather than route handler execution. This explains why messages queue successfully (producer works) but consumers never invoke (initialization never completes).

Cause #2

Vercel resolves function paths in vercel.json relative to the configured Root Directory. When Root Directory is set to apps/client , the path app/api/queues/my-topic/route.ts should correctly resolve to apps/client/app/api/queues/my-topic/route.ts from the monorepo root.

Potential issue: Multiple vercel.json files in monorepos can create ambiguity. Path resolution bugs in experimentalTriggers processing could prevent queue infrastructure from discovering the consumer endpoint.

Cause #3

While cacheComponents: true primarily affects GET request caching, its architectural changes in Next.js 16 introduce broader build-time implications:

  • Significantly increased memory usage during builds (SIGKILL OOM errors documented)
  • Changes to route handler processing and deployment manifest generation
  • Requires Node.js runtime; incompatible with Edge Runtime expectations

POST route handlers remain uncached, but build output format changes could affect how Vercel’s queue infrastructure registers experimentalTriggers .

Cause #4

Vercel’s internal queue infrastructure automatically bypasses Deployment Protection and Attack Challenge Mode for service-to-service calls. However, custom WAF rules could still block invocations if misconfigured. Consumer functions are air-gapped—no public URL exists—so only Vercel’s queue infrastructure can invoke them.

Cause #5

The absence of runtime logs indicates the consumer function initialization never completes, suggesting a platform-level failure rather than application code error. Consumer Groups are created at deployment time when experimentalTriggers are registered (see here). Missing Consumer Group confirms registration failure.


Let me know if any of that helps!

Thank you for bringing this to our attention. To ensure this is investigated with the necessary priority and privacy, please report all security-related concerns, potential exploits, or abuse directly to the Vercel Security Team.

Please submit your report here: Report Abuse On Vercel

Reporting via this official channel is the fastest way to reach our security engineers and ensures that sensitive information is handled in a secure environment rather than a public forum.