nextjs - 💡(How to fix) Fix Route Handler POST requests fail with ky/Axios but not fetch [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#91280Fetched 2026-04-08 00:42:00
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
0
Timeline (top)
labeled ×5closed ×1commented ×1issue_type_added ×1

Fix Action

Fix / Workaround

  • The issue only appears when the request originates from a Next.js Route Handler.
  • The same code works perfectly in:
    • Node.js scripts,
    • client-side components,
    • and when using the native fetch() API.
  • This suggests a difference in how Next.js patches or polyfills fetch() internally, which may affect libraries that wrap or rely on it.
  • The external API returns 400 only when ky or Axios+fetch adapter are used, even though the request body and headers appear identical.
  • Reproduced both locally and on Vercel.

Code Example

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:28:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6030
  Available memory (MB): 18432
  Available CPU cores: 11
Binaries:
  Node: 24.14.0
  npm: 11.9.0
  Yarn: 1.22.22
  pnpm: 10.29.3
Relevant Packages:
  next: 16.1.6 // Latest available version is detected (16.1.6).
  eslint-config-next: N/A
  react: 19.2.3
  react-dom: 19.2.3
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/user/my-minimal-nextjs-issue-reproduction

To Reproduce

  1. Create a Next.js API Route Handler (App Router) that performs a POST request to an external API.
  2. Call the external API using:
    • ky (which uses fetch under the hood), or
    • Axios with the fetch adapter.
  3. Run the API route using next dev or next start.
  4. Observe that the external API responds with 400 Bad Request.
  5. Replace the ky/Axios call with a direct fetch() call using the same URL, headers, and body.
  6. Observe that the request succeeds and does not return 400.
  7. Run the same ky/Axios code in:
    • a standalone Node.js script, or
    • a client-side React component
      → The request succeeds normally (no 400).

Current vs. Expected behavior

Current behavior:

  • When calling an external API from a Next.js Route Handler, POST requests made with:
    • ky, or
    • Axios using the fetch adapter
      consistently return 400 Bad Request.
  • The same request made with the built‑in fetch() works correctly.
  • The issue only occurs inside Route Handlers.
  • The issue does not occur:
    • in client-side React components,
    • in standalone Node.js scripts,
    • or when using fetch() directly.

Expected behavior:

  • ky and Axios (with fetch adapter) should behave identically to the native fetch() implementation in Route Handlers.
  • POST requests should not fail with 400 when using these libraries.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:28:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6030
  Available memory (MB): 18432
  Available CPU cores: 11
Binaries:
  Node: 24.14.0
  npm: 11.9.0
  Yarn: 1.22.22
  pnpm: 10.29.3
Relevant Packages:
  next: 16.1.6 // Latest available version is detected (16.1.6).
  eslint-config-next: N/A
  react: 19.2.3
  react-dom: 19.2.3
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Route Handlers, Runtime, Connection, Headers, Not sure

Which stage(s) are affected? (Select all that apply)

next dev (local), next start (local), Vercel (Deployed)

Additional context

  • The issue only appears when the request originates from a Next.js Route Handler.
  • The same code works perfectly in:
    • Node.js scripts,
    • client-side components,
    • and when using the native fetch() API.
  • This suggests a difference in how Next.js patches or polyfills fetch() internally, which may affect libraries that wrap or rely on it.
  • The external API returns 400 only when ky or Axios+fetch adapter are used, even though the request body and headers appear identical.
  • Reproduced both locally and on Vercel.

extent analysis

Fix Plan

To resolve the issue with ky and Axios (with fetch adapter) returning 400 Bad Request in Next.js Route Handlers, we need to modify how these libraries are used within the Next.js environment.

The issue seems to stem from how Next.js handles or patches the fetch API internally, which affects libraries that wrap or rely on it.

Here are the steps to fix the issue:

  • Use the node-fetch library directly instead of relying on ky or Axios with the fetch adapter. This approach ensures consistency with Next.js's internal handling of fetch.
  • Configure Axios to use the http adapter instead of the fetch adapter when making requests from Next.js Route Handlers. This bypasses any potential issues with Next.js's fetch patching.

Example Code

Using node-fetch directly:

import fetch from 'node-fetch';

export default async function handler(req, res) {
  const response = await fetch('https://example.com/api/endpoint', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ key: 'value' }),
  });

  const data = await response.json();
  res.status(200).json(data);
}

Configuring Axios to use the http adapter:

import axios from 'axios';
import { createHttpAdapter } from 'axios/lib/adapters/http';

const httpAdapter = createHttpAdapter();

const instance = axios.create({
  adapter: httpAdapter,
});

export default async function handler(req, res) {
  const response = await instance.post('https://example.com/api/endpoint', {
    key: 'value',
  }, {
    headers: {
      'Content-Type': 'application/json',
    },
  });

  res.status(200).json(response.data);
}

Verification

To verify that the fix worked, follow these steps:

  • Deploy the updated code to your local environment or Vercel.
  • Test the API route using a tool like Postman or cURL.
  • Confirm that the request no longer returns a 400 Bad Request status code.

Extra Tips

  • Ensure you are using the latest versions of node-fetch, axios, and next to minimize potential compatibility issues.
  • If issues persist, consider logging the request and response headers to identify any discrepancies between the working fetch calls and the non-working ky/Axios calls.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING