n8n-io/n8n · error · NodeOperationError

There was an error: "The workflow did not return a response"

Error message

There was an error: "The workflow did not return a response"

What it means

Thrown by WorkflowToolService.executeSubWorkflow (v2) when, after a successful execution, the expected response slot is undefined. With returnAllItems=true it fires when receivedData.data[0] has no items; otherwise when receivedData.data[0][0].json is undefined. The tool needs a concrete payload to return.

Source

Thrown at packages/@n8n/nodes-langchain/nodes/tools/ToolWorkflow/v2/utils/WorkflowToolService.ts:285

					executionId: workflowProxy.$execution.id,
					workflowId: workflowProxy.$workflow.id,
				},
				returnLastRunOnly: true, // The tool's answer is the sub-workflow's final-run output, not its internal multi-run computation.
			});
			// Set sub-workflow execution id so it can be used in other places
			this.subExecutionId = receivedData.executionId;
		} catch (error) {
			throw new NodeOperationError(context.getNode(), error as Error);
		}

		let response: IDataObject | INodeExecutionData[] | undefined;
		if (this.returnAllItems) {
			response = receivedData?.data?.[0]?.length ? receivedData.data[0] : undefined;
		} else {
			response = receivedData?.data?.[0]?.[0]?.json;
		}
		if (response === undefined) {
			throw new NodeOperationError(
				context.getNode(),
				'There was an error: "The workflow did not return a response"',
			);
		}

		return { response, subExecutionId: receivedData.executionId };
	}

	/**
	 * Gets the sub-workflow info based on the source and executes it.
	 * This function will be called as part of the tool execution (from the toolHandler)
	 */
	private async runFunction(
		context: ISupplyDataFunctions | IExecuteFunctions,
		query: string | IDataObject,
		itemIndex: number,
		runManager?: CallbackManagerForToolRun,
	): Promise<IDataObject | INodeExecutionData[]> {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Open the sub-workflow and run it with the same input the agent sent; confirm output 0 emits ≥1 item.
  2. Add a terminal Set node that always emits a default item (e.g. { response: 'No results' }).
  3. If using 'Return All Items', ensure the sub-workflow's main output is a non-empty array.
  4. Verify the sub-workflow's last executed node isn't on a dead branch.

Example fix

// before: sub-workflow IF(false) → empty main branch → throws
// after: merge both IF branches into a single terminal Set node
//   that always emits { response: {{ $json.answer || 'No results' }} }
Defensive patterns

Strategy: validation

Validate before calling

const slot = this.returnAllItems ? receivedData?.data?.[0] : receivedData?.data?.[0]?.[0]?.json;
if (slot === undefined) throw new Error('Sub-workflow produced no output; add a terminal default item');

Type guard

function hasOutputItem(d: ExecuteWorkflowData, all: boolean): boolean {
  return all ? (d?.data?.[0]?.length ?? 0) > 0 : d?.data?.[0]?.[0]?.json !== undefined;
}

Try / catch

try { return await this.executeSubWorkflow(...); }
catch (e) { /* return a default response or rethrow with guidance */ }

Prevention

When it happens

Trigger: Sub-workflow runs but its terminal main-output node emits zero items; the answer lives on a non-zero run or output; returnLastRunOnly strips the run that held the data.

Common situations: Conditional sub-workflow branches that produce no output for certain inputs; sub-workflows whose final node is an error-handling branch that returns []; misconfigured output routing.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/775c793790848185. Report an issue: GitHub.