nextjsvercelserverlessdebugging

The Silent Killer of Vercel Cron Jobs in Next.js (405 Method Not Allowed)

Arun Batchu, Cascade (AI)·February 28, 2026·4 min read
Share

You've built a powerful AI agent as a Next.js API route. You tested it with curl using a POST request — works perfectly. You add it to vercel.json as a cron job, deploy to production, and wait. The scheduled time comes and goes. Nothing happens. No database entries, no emails, no generated images.

When you check your Vercel logs, you don't see any application errors. Instead, buried in the raw HTTP traffic, you spot this tiny, easily-missed log:

GET 405 /api/your-cron-endpoint

The Root Cause

  • Next.js App Router is strict: If you only export export async function POST, Next.js rejects any other HTTP method with a 405 Method Not Allowed — immediately, at the routing level, before your code runs.
  • Vercel Cron defaults to GET: Unless told otherwise, Vercel's scheduler invokes cron endpoints via HTTP GET requests.

The cron fires, Next.js rejects the GET silently, no application error is thrown, and nothing in your logs points to the real problem.

The Fix

Add a GET alias in your route file that delegates to POST:

export async function POST(request) {
  // your cron logic
  return NextResponse.json({ status: 'success' });
}
 
export async function GET(request) {
  return POST(request);
}

Security Warning

Opening a GET route means anyone can trigger it from a browser. Always verify Vercel's x-vercel-cron-auth-token header before executing expensive operations:

export async function POST(request) {
  const isVercelCron = request.headers.get('x-vercel-cron-auth-token') ||
    request.headers.get('user-agent')?.includes('vercel-cron');
  const authHeader = request.headers.get('authorization');
 
  if (!isVercelCron && authHeader !== `Bearer ${process.env.AGENT_SECRET}`) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }
 
  // safe to run
}

Summary

  1. Check Vercel traffic logs for 405 errors on your cron path.
  2. Add export async function GET(request) { return POST(request); } to your route.
  3. Secure the endpoint with Vercel's cron auth headers.

🧠 Special thanks to Gemini 3.1 Pro High Thinking (via Windsurf's Cascade) for the deep reasoning that cracked this silent bug open when all normal application logs came up empty.

Found this useful? Share it.
Share

About the author

If this resonated, reach out. Here's how to continue the conversation.

Arun Batchu

Arun Batchu

Founder & Principal Advisor

I can help you separate AI hype from real operating advantage — and design experiments that build evidence faster than opinions do.