From c918e85e91528da910836f0fa5c74ca3714daff1 Mon Sep 17 00:00:00 2001 From: Ofek Danny <63648262+OfekDanny@users.noreply.github.com> Date: Sun, 26 Apr 2026 13:37:24 +0300 Subject: [PATCH] fix(fetch-adapter): set User-Agent header to match http adapter (#10772) The fetch adapter was not setting a User-Agent header, causing requests to use Node.js's default 'node' user agent instead of 'axios/'. This mirrors the existing behavior in the HTTP adapter. Fixes #7494 Co-authored-by: Ofek Danny Co-authored-by: Jay --- lib/adapters/fetch.js | 4 +++ tests/unit/adapters/fetch.test.js | 47 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/lib/adapters/fetch.js b/lib/adapters/fetch.js index 7653c491..bc79778d 100644 --- a/lib/adapters/fetch.js +++ b/lib/adapters/fetch.js @@ -12,6 +12,7 @@ import { import resolveConfig from '../helpers/resolveConfig.js'; import settle from '../core/settle.js'; import estimateDataURLDecodedBytes from '../helpers/estimateDataURLDecodedBytes.js'; +import { VERSION } from '../env/data.js'; const DEFAULT_CHUNK_SIZE = 64 * 1024; @@ -277,6 +278,9 @@ const factory = (env) => { } } + // Set User-Agent header if not already set (fetch defaults to 'node' in Node.js) + headers.set('User-Agent', 'axios/' + VERSION, false); + const resolvedOptions = { ...fetchOptions, signal: composedSignal, diff --git a/tests/unit/adapters/fetch.test.js b/tests/unit/adapters/fetch.test.js index c82c7bb0..e8e25fa7 100644 --- a/tests/unit/adapters/fetch.test.js +++ b/tests/unit/adapters/fetch.test.js @@ -14,6 +14,7 @@ import stream from 'stream'; import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; import util from 'util'; import NodeFormData from 'form-data'; +import { VERSION } from '../../../lib/env/data.js'; const SERVER_PORT = 8010; const LOCAL_SERVER_URL = `http://localhost:${SERVER_PORT}`; @@ -619,6 +620,52 @@ describe.runIf(typeof fetch === 'function')('supports fetch with nodejs', () => }); }); + describe('fetch adapter - User-Agent header', () => { + it('should set User-Agent header to axios/ by default', async () => { + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ userAgent: req.headers['user-agent'] })); + }, + { port: SERVER_PORT } + ); + + try { + const { data } = await fetchAxios.post(`http://localhost:${server.address().port}/`, { + payload: 'test', + }); + + assert.strictEqual(data.userAgent, `axios/${VERSION}`); + } finally { + await stopHTTPServer(server); + } + }); + + it('should not override a user-provided User-Agent header', async () => { + const customUA = 'my-custom-agent/1.0'; + + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ userAgent: req.headers['user-agent'] })); + }, + { port: SERVER_PORT } + ); + + try { + const { data } = await fetchAxios.post( + `http://localhost:${server.address().port}/`, + { payload: 'test' }, + { headers: { 'User-Agent': customUA } } + ); + + assert.strictEqual(data.userAgent, customUA); + } finally { + await stopHTTPServer(server); + } + }); + }); + describe('env config', () => { it('should respect env fetch API configuration', async () => { const { data, headers } = await fetchAxios.get('/', {