Custom node can't execute base nodes

Hi node devs :sunglasses:

I have a small problem with a custom node.

I wanted to modify the base node “Execute Workflow” a little bit. The customizations work, but only as long as the original “Execute Workflow” node is executed before. Otherwise I get the error message “The node-type ‘n8n-nodes-base.XXXXXX’ is not known!”

Apparently my custom node cannot execute a base node. Is there a workaround for this?

Which interestingly white also does not work: Copy the “dist” content into the “n8n\node_modules\n8n-nodes-base\dist\nodes” directory and modify the package.json accordingly. Node is recognized as n8n-nodes-base but it does not fix the error.

What worked:
Designating the node as ExecuteWorkflow and overwriting base node with it.
BUT I DON’T WANT TO LEAVE IT LIKE THAT.

Hi @BillAlex, I am sorry to hear you’re having trouble. Can you confirm how exactly you have customized the node? As in which changes exactly would one need to make to the n8n base repository to reproduce the problem?

Hi @MutedJam,

to produce the error you just have to load my custom node via “npm link”, drop in and execute an workflow with it :wink:

Starter Repo was my base…

The customizations are related to some suggestions already made.
The execution node should (still) get the possibility to pass data manually - so you save a node before for the pass. And for me very important: The possibility to output true/false.

Here are the raw data:

Summary
import {readFile as fsReadFile} from 'fs/promises';
import {IExecuteFunctions} from 'n8n-core';
import {
	IExecuteWorkflowInfo,
	INodeExecutionData,
	INodeType,
	INodeTypeDescription,
	IWorkflowBase,
	NodeOperationError,
} from 'n8n-workflow';

export class Middleware implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Middleware',
		name: 'middleware',
		icon: 'fa:sign-in-alt',
		group: ['transform'],
		version: 1,
		subtitle: '={{"Workflow: " + $parameter["workflowId"]}}',
		description: 'Execute another workflow',
		defaults: {
			name: 'Middleware',
			color: '#ff6d5a',
		},
		inputs: ['main'],
		// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
		outputs: ['main', 'main'],
		outputNames: ['true', 'false'],
		properties: [
			{
				displayName: 'Source',
				name: 'source',
				type: 'options',
				options: [
					{
						name: 'Database',
						value: 'database',
						description: 'Load the workflow from the database by ID',
					},
					{
						name: 'Local File',
						value: 'localFile',
						description: 'Load the workflow from a locally saved file',
					},
					{
						name: 'Parameter',
						value: 'parameter',
						description: 'Load the workflow from a parameter',
					},
					{
						name: 'URL',
						value: 'url',
						description: 'Load the workflow from an URL',
					},
				],
				default: 'database',
				description: 'Where to get the workflow to execute from',
			},

			// ----------------------------------
			//         source:database
			// ----------------------------------
			{
				displayName: 'Workflow ID',
				name: 'workflowId',
				type: 'string',
				displayOptions: {
					show: {
						source: ['database'],
					},
				},
				default: '',
				required: true,
				description: 'The workflow to execute',
			},

			// ----------------------------------
			//         source:localFile
			// ----------------------------------
			{
				displayName: 'Workflow Path',
				name: 'workflowPath',
				type: 'string',
				displayOptions: {
					show: {
						source: ['localFile'],
					},
				},
				default: '',
				placeholder: '/data/workflow.json',
				required: true,
				description: 'The path to local JSON workflow file to execute',
			},

			// ----------------------------------
			//         source:parameter
			// ----------------------------------
			{
				displayName: 'Workflow JSON',
				name: 'workflowJson',
				type: 'string',
				typeOptions: {
					alwaysOpenEditWindow: true,
					editor: 'json',
					rows: 10,
				},
				displayOptions: {
					show: {
						source: ['parameter'],
					},
				},
				default: '\n\n\n',
				required: true,
				description: 'The workflow JSON code to execute',
			},

			// ----------------------------------
			//         source:url
			// ----------------------------------
			{
				displayName: 'Workflow URL',
				name: 'workflowUrl',
				type: 'string',
				displayOptions: {
					show: {
						source: ['url'],
					},
				},
				default: '',
				placeholder: 'https://example.com/workflow.json',
				required: true,
				description: 'The URL from which to load the workflow from',
			},
			{
				displayName:
					'Any data you pass into this node will be output by the start node of the workflow to be executed. <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow/" target="_blank">More info</a>',
				name: 'executeWorkflowNotice',
				type: 'notice',
				default: '',
			},
		],
	};

	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		const items = this.getInputData();
		const source = this.getNodeParameter('source', 0) as string;

		const workflowInfo: IExecuteWorkflowInfo = {};

		try {
			if (source === 'database') {
				// Read workflow from database
				workflowInfo.id = this.getNodeParameter('workflowId', 0) as string;
			} else if (source === 'localFile') {
				// Read workflow from filesystem
				const workflowPath = this.getNodeParameter('workflowPath', 0) as string;

				let workflowJson;
				try {
					workflowJson = (await fsReadFile(workflowPath, {encoding: 'utf8'})) as string;
				} catch (error) {
					if (error.code === 'ENOENT') {
						throw new NodeOperationError(
							this.getNode(),
							`The file "${workflowPath}" could not be found.`,
						);
					}

					throw error;
				}

				workflowInfo.code = JSON.parse(workflowJson) as IWorkflowBase;
			} else if (source === 'parameter') {
				// Read workflow from parameter
				const workflowJson = this.getNodeParameter('workflowJson', 0) as string;
				workflowInfo.code = JSON.parse(workflowJson) as IWorkflowBase;
			} else if (source === 'url') {
				// Read workflow from url
				const workflowUrl = this.getNodeParameter('workflowUrl', 0) as string;

				const requestOptions = {
					headers: {
						accept: 'application/json,text/*;q=0.99',
					},
					method: 'GET',
					uri: workflowUrl,
					json: true,
					gzip: true,
				};

				const response = await this.helpers.request(requestOptions);
				workflowInfo.code = response;
			}

// My changes...
			const receivedData = (await this.executeWorkflow(workflowInfo, items))[0];
			console.log(JSON.stringify(receivedData));
			return (receivedData[0].json.__middleware === true) ? [receivedData, []] : [[], receivedData];
		} catch (error) {
			if (this.continueOnFail()) {
				return this.prepareOutputData([{json: {error: error.message}}]);
			}

			throw error;
		}
	}
}

2 rows at the end was added/modified and the output props in description…

I don’t know, but the nodes are loaded as needed. Right?
If I “execute” (paused is enough) all the nodes that I want to use in the SubWorkflow, the custom node can run through. If not they are not registered.
The base node “Execution Node” seems to register all necessary ones at some point. But obviously the node does not do that itself. The server must recognize at some point that additional nodes must be loaded now.

Hi @BillAlex, you mean this starter repo documented here, right? This worked fine for me in the past (for example here), though I haven’t tried copying base nodes yet.

I shall block some time later this week for a closer look, though perhaps our master node builder @marcus know what’s up here?

Hi @BillAlex,
I copied your custom Execute Workflow node called Middleware into a starter repo and linked it up. I am getting similar error messages as you described.

As soon as I place an original Execute Workflow node somewhere inside my workflow it works.

Just to be sure I also tried using the original Execute Workflow code without your modifications resulting in the same error.

The Execute Workflow node itself is not responsible for loading any nodes, it just executes the workflow. I am not sure what is happening here, I can only assume that we may have some custom logic outside the Execute Workflow node to make it work.

Can you publish your node-starter-repo including your Middleware node on github for further investigation?

1 Like

I have publish our nodes:

Sorry for delay…

@MutedJam Yes I have use the starter repo.

And, what I probably shouldn’t have done, I updated the dependencies (n8n-core, n8n-workflow among others). Because now I can’t publish nodes on npm. ESLint error: “No files matching the pattern “credentials” were found. Please check for typing mistakes in the pattern.” I have no idea about ESLint. I have played around with a few settings without success.
But I don’t see any difference to other repos. My nodes still “work” locally.
Sorry for Off-Topic…

@marcus The problem seems to have been fixed with v0.199.0. I can use my Custom Execute Node without problems.

1 Like

@BillAlex good to know. Happy that it’s working for you.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.