NodeApiError: nativeProtocol.request is not a function

Hello everyone,

I’m experiencing a strange issue with my custom n8n nodes. Locally everything works fine, but in the test environment I get this error:

NodeApiError: nativeProtocol.request is not a function

I’m using a helper function pattern

// Helper functions
export function getMakeAxiosRequestFunction(
	functions: IExecuteFunctions,
	pairedItem: INodeExecutionData['pairedItem'],
): {
	(request: {
		(): Promise<AxiosResponse<unknown, unknown>>;
	}): Promise<INodeExecutionData[] | NodeExecutionWithMetadata[]>;
} {
	return async (request) => await handleRequest(request, functions, pairedItem);
}

export async function handleRequest(
  request: { (): Promise<AxiosResponse<unknown, unknown>> },
  functions: IExecuteFunctions,
  pairedItem: INodeExecutionData['pairedItem'],
): Promise<INodeExecutionData[] | NodeExecutionWithMetadata[]> {
  try {
    // ... success handling
  } catch (e) {
    const error = new NodeApiError(functions.getNode(), e as unknown as JsonObject, {
      message: e.message,
      httpCode: axios.isAxiosError(e) ? e.response?.status?.toString() : undefined,
    });
    // ... error handling
  }
}

In my custom node implementation, I call:

async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
       
        // rest code ...

		const axiosInstance = axios.create({
			baseURL: credentials.baseUrl,
		});

		for (let i = 0; i < items.length; i++) {
            // rest code ... 
		   const makeRequest = getMakeAxiosRequestFunction(this, i);
            // rest code ...
           if (operation === 'someName') {
				returnData.push(
					await makeRequest(async () => await axiosInstance.get('/api/example/data')),
				);
			}

        }

}

Questions

  • Could this be related to race conditions or parallel execution in multi-main setups?
  • Are there known issues with NodeApiError constructor in certain n8n environments?
  • Is there something wrong with my approach to error handling in helper functions?

Any help would be greatly appreciated!

Thanks

What is the error message (if any)?

NodeApiError: nativeProtocol.request is not a function

Share the output returned by the last node

Information on your n8n setup

  • n8n version: 2.4.6
  • Database (default: SQLite):Postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main):-
  • Running n8n via (Docker, npm, n8n cloud, desktop app):Docker
  • Operating system:-

hello @Enestacy

Why are you calling axios directly?
You should use n8n interfaces for this:

this.helpers.httpRequestWithAuthentication.call()
or
this.helpers.httpRequest.call()
or other, they are located in the interfaces.ts of the n8n workflow package.

You can check for errors with

try {
	return await this.helpers.httpRequestWithAuthentication.call(this, 'myNodeApi', options);
} catch (error) {
	throw new NodeApiError(this.getNode(), error as JsonObject);
}

full example (may have extra info):

import type {
	IDataObject,
	IExecuteFunctions,
	IHookFunctions,
	IHttpRequestMethods,
	ILoadOptionsFunctions,
	IHttpRequestOptions,
	IWebhookFunctions,
	JsonObject,
} from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';

export async function apiRequest(
	this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
	method: IHttpRequestMethods,
	endpoint: string,
	body: IDataObject | FormData,
	query?: IDataObject,
	option: IDataObject = {}
): Promise<IDataObject> {
	const credentials = await this.getCredentials('myNodeApi');
	const baseUrl = (credentials?.isHttp ? 'http://' : 'https://') + credentials?.host;

	query = query || {};

	const disableSslChecks = credentials.isHttp
		? true
		: (credentials.allowUnauthorizedCerts as boolean);

	let options: IHttpRequestOptions = {
		method,
		url: `${baseUrl}/${endpoint}`,
		qs: query,
		body,
		returnFullResponse: false,
		json: true,
		headers: { 'content-type': 'application/json' },
		skipSslCertificateValidation: disableSslChecks,
		ignoreHttpStatusErrors: false,
	};

	if (Object.keys(option).length > 0) {
		options = Object.assign({}, options, option);
	}

	if (Object.keys(body).length === 0) {
		delete options.body;
	}

	if (Object.keys(query).length === 0) {
		delete options.qs;
	}

	try {
		return await this.helpers.httpRequestWithAuthentication.call(this, 'myNodeApi', options);
	} catch (error) {
		throw new NodeApiError(this.getNode(), error as JsonObject);
	}
}
1 Like

Hi @Enestacy

Building on the previous reply, the core issue is not parallelism or environment differences, but the type of error object you are passing into NodeApiError. When you call Axios directly, the thrown error is a plain Axios error, while NodeApiError expects an error produced by n8n’s own HTTP helpers, which include extra internal request metadata. Without that metadata, the constructor can break and produce the nativeProtocol.request is not a function message.

Using this.helpers.httpRequestWithAuthentication (or httpRequest) ensures both the request and the resulting errors go through n8n’s internal pipeline, so wrapping the error with NodeApiError works reliably in every environment (local, Docker, multi-instance). This aligns your custom node with how core nodes handle HTTP and avoids these low-level protocol issues.

If you absolutely need to keep Axios, a temporary workaround is to not pass the raw Axios error into NodeApiError and instead throw a simpler error type. But the definitive fix is to migrate the request to n8n’s helpers so your node participates fully in n8n’s request and error handling model.

1 Like

Thanks for replies!
I’ll try to use n8n helpers for http requests. Hope it will help

The helpers are a solid choice.
Let us know if that fixes it.