fix(core): AI agent node data accessibility (#18757)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Csaba Tuncsik
2025-09-01 17:37:16 +02:00
committed by GitHub
parent 897c55aefe
commit f0e9221cb3
6 changed files with 724 additions and 68 deletions

View File

@@ -402,12 +402,17 @@ export class WorkflowDataProxy {
!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName) &&
!getPinDataIfManualExecution(that.workflow, nodeName, that.mode)
) {
throw new ExpressionError('Referenced node is unexecuted', {
throw new ExpressionError(`Node '${nodeName}' hasn't been executed`, {
messageTemplate:
'An expression references this node, but the node is unexecuted. Consider re-wiring your nodes or checking for execution first, i.e. {{ $if( $("{{nodeName}}").isExecuted, <action_if_executed>, "") }}',
functionality: 'pairedItem',
descriptionKey: isScriptingNode(nodeName, that.workflow)
? 'pairedItemNoConnectionCodeNode'
: 'pairedItemNoConnection',
type: 'no_execution_data',
nodeCause: nodeName,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
type: 'no_node_execution_data',
descriptionKey: 'noNodeExecutionData',
nodeCause: nodeName,
});
}
@@ -496,11 +501,16 @@ export class WorkflowDataProxy {
name = name.toString();
if (!node) {
throw new ExpressionError("Referenced node doesn't exist", {
throw new ExpressionError('Referenced node does not exist', {
messageTemplate: 'Make sure to double-check the node name for typos',
functionality: 'pairedItem',
descriptionKey: isScriptingNode(nodeName, that.workflow)
? 'pairedItemNoConnectionCodeNode'
: 'pairedItemNoConnection',
type: 'paired_item_no_connection',
nodeCause: nodeName,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
nodeCause: nodeName,
descriptionKey: 'nodeNotFound',
});
}
@@ -514,31 +524,36 @@ export class WorkflowDataProxy {
return undefined;
}
// Ultra-simple execution-based validation: if no execution data exists, throw error
if (executionData.length === 0) {
if (that.workflow.getParentNodes(nodeName).length === 0) {
throw new ExpressionError('No execution data available', {
messageTemplate:
'No execution data available to expression under %%PARAMETER%%',
descriptionKey: 'noInputConnection',
nodeCause: nodeName,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
type: 'no_input_connection',
});
}
throw new ExpressionError('No execution data available', {
throw new ExpressionError(`Node '${nodeName}' hasn't been executed`, {
messageTemplate:
'An expression references this node, but the node is unexecuted. Consider re-wiring your nodes or checking for execution first, i.e. {{ $if( $("{{nodeName}}").isExecuted, <action_if_executed>, "") }}',
functionality: 'pairedItem',
descriptionKey: isScriptingNode(nodeName, that.workflow)
? 'pairedItemNoConnectionCodeNode'
: 'pairedItemNoConnection',
type: 'no_execution_data',
nodeCause: nodeName,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
type: 'no_execution_data',
});
}
if (executionData.length <= that.itemIndex) {
throw new ExpressionError(`No data found for item-index: "${that.itemIndex}"`, {
runIndex: that.runIndex,
itemIndex: that.itemIndex,
});
throw new ExpressionError(
`"${nodeName}" node has ${executionData.length} item(s) but you're trying to access item ${that.itemIndex}`,
{
messageTemplate:
'Adjust your expression to access an existing item index (0-{{maxIndex}})',
functionality: 'pairedItem',
descriptionKey: 'pairedItemInvalidIndex',
type: 'no_execution_data',
nodeCause: nodeName,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
},
);
}
if (['data', 'json'].includes(name)) {
@@ -1066,12 +1081,17 @@ export class WorkflowDataProxy {
!that?.runExecutionData?.resultData?.runData.hasOwnProperty(nodeName) &&
!getPinDataIfManualExecution(that.workflow, nodeName, that.mode)
) {
throw createExpressionError('Referenced node is unexecuted', {
throw createExpressionError(`Node '${nodeName}' hasn't been executed`, {
messageTemplate:
'An expression references this node, but the node is unexecuted. Consider re-wiring your nodes or checking for execution first, i.e. {{ $if( $("{{nodeName}}").isExecuted, <action_if_executed>, "") }}',
functionality: 'pairedItem',
descriptionKey: isScriptingNode(nodeName, that.workflow)
? 'pairedItemNoConnectionCodeNode'
: 'pairedItemNoConnection',
type: 'no_execution_data',
nodeCause: nodeName,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
type: 'no_node_execution_data',
descriptionKey: 'noNodeExecutionData',
nodeCause: nodeName,
});
}
};
@@ -1114,7 +1134,7 @@ export class WorkflowDataProxy {
let contextNode = that.contextNodeName;
if (activeNode) {
const parentMainInputNode = that.workflow.getParentMainInputNode(activeNode);
contextNode = parentMainInputNode.name ?? contextNode;
contextNode = parentMainInputNode?.name ?? contextNode;
}
const parentNodes = that.workflow.getParentNodes(contextNode);
if (!parentNodes.includes(nodeName)) {