n8n-io/n8n · error · NodeOperationError

Invalid hitl input for tool ${toolkitTool.name}

Error message

Invalid hitl input for tool ${toolkitTool.name}

What it means

Thrown by the ToolExecutor node during gated-tool (human-in-the-loop) handling when the resolved hitl input for the given node is a string rather than an object. Gated tools expect structured approval/parameter data; a string input is not addressable by field and is rejected before being passed to the tool.

Source

Thrown at packages/@n8n/nodes-langchain/nodes/ToolExecutor/ToolExecutor.node.ts:131

		try {
			for (const tool of toolInputs) {
				// Handle toolkits
				if (tool && typeof (tool as Toolkit).getTools === 'function') {
					const toolsInToolkit = (tool as Toolkit).getTools();
					for (const toolkitTool of toolsInToolkit) {
						if (!(toolkitTool instanceof Tool || toolkitTool instanceof StructuredTool)) {
							continue;
						}

						if (toolName === toolkitTool.name) {
							if (hasGatedToolNodeName(toolkitTool.metadata) && node) {
								const toolInput: { toolParameters: unknown } = {
									toolParameters: getQueryData(toolName) ?? {},
								};
								const hitlInput = getQueryData(node);
								if (typeof hitlInput === 'string') {
									throw new NodeOperationError(
										this.getNode(),
										`Invalid hitl input for tool ${toolkitTool.name}`,
									);
								}

								// handle code tool which uses a string input, but it should be converted to an object
								const requiresObjectInput =
									toolkitTool.metadata.originalSchema &&
									toolkitTool.metadata.originalSchema instanceof ZodObject;
								if (typeof toolInput.toolParameters === 'string' && requiresObjectInput) {
									toolInput.toolParameters = convertValueBySchema(
										toolInput.toolParameters,
										toolkitTool.metadata.originalSchema,
									);
								}

								const hitlMetadata = extractHitlMetadata(
									toolkitTool.metadata,

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Ensure the resume/approval payload for the gated node is a JSON object matching the tool's expected input shape.
  2. If using a Webhook/Form to resume, parse the body into an object before submitting.
  3. Validate the wait-node output schema and align it with what the gated tool expects.

Example fix

// before: hitl resume value = "approved"
// after: hitl resume value = { "approved": true, "comment": "ok" }
Defensive patterns

Strategy: type-guard

Validate before calling

const hitlInput = getQueryData(node);
if (typeof hitlInput === 'string') throw new Error('Provide HITL input as a JSON object');

Type guard

function isHitlObject(v): v is Record<string, unknown> {
  return v != null && typeof v === 'object' && !Array.isArray(v);
}

Prevention

When it happens

Trigger: Inside the toolkit loop, when toolName === toolkitTool.name, hasGatedToolNodeName(metadata) && node is true, getQueryData(node) returns hitlInput. If `typeof hitlInput === 'string'`, it throws NodeOperationError 'Invalid hitl input for tool <name>'. Fires when the HITL approval payload coming back for the gated node is a plain string.

Common situations: The waiting/resume workflow submits a string approval value instead of a JSON object; the front-end or webhook resume payload is malformed; an expression that should yield an object yields its stringified form; mismatch between the gated tool's expected schema and the resume data.

Related errors


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