n8n-io/n8n · error · NodeOperationError

Failed to parse query: ${(error as Error).message}

Error message

Failed to parse query: ${(error as Error).message}

What it means

Thrown by the ToolExecutor node when the 'query' parameter is a string that fails JSON.parse. The node expects query to be either a JSON string or an object that maps tool names to their input arguments; unparseable text cannot be turned into that map.

Source

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

		// If there are approved HITL tools, we need to execute the gated tools first
		const hitlResult = processHitlResponses(response, 0);

		if (hitlResult.hasApprovedHitlTools && hitlResult.pendingGatedToolRequest) {
			// Return the gated tool request immediately
			// The Agent will resume after the gated tool executes
			return hitlResult.pendingGatedToolRequest;
		}

		const query = this.getNodeParameter('query', 0, {}) as string | object;
		const toolName = this.getNodeParameter('toolName', 0, '') as string;
		const node = this.getNodeParameter('node', 0, '') as string;

		let parsedQuery: Record<string, unknown>;

		try {
			parsedQuery = typeof query === 'string' ? JSON.parse(query) : query;
		} catch (error) {
			throw new NodeOperationError(
				this.getNode(),
				`Failed to parse query: ${(error as Error).message}`,
			);
		}

		const getQueryData = (name: string) => {
			// node names in query may have underscores in place of spaces, use it for accessing the query data.
			return (get(parsedQuery, name, null) ?? get(parsedQuery, name.replaceAll(' ', '_'), null)) as
				| Record<string, unknown>
				| string
				| null;
		};

		const resultData: INodeExecutionData[] = [];
		const toolInputs = await this.getInputConnectionData(NodeConnectionTypes.AiTool, 0);

		if (!toolInputs || !Array.isArray(toolInputs)) {
			throw new NodeOperationError(this.getNode(), 'No tool inputs found');

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Provide query as a valid JSON object string, e.g. '{"search": {"q": "n8n"}}'.
  2. If passing an object via an expression, ensure the expression yields an object, not its stringified-but-invalid form.
  3. Use a Set node upstream to construct the query object and reference it.
  4. Validate the JSON in a scratch tool before pasting it into the parameter.

Example fix

// before: query = 'search for n8n'
// after: query = '{ "search": { "q": "n8n" } }'
Defensive patterns

Strategy: validation

Validate before calling

function asQueryObject(query) {
  if (typeof query !== 'string') return query;
  const obj = JSON.parse(query); // throws clearly if invalid
  if (obj === null || typeof obj !== 'object') throw new Error('query must be a JSON object');
  return obj;
}

Try / catch

try {
  parsedQuery = typeof query === 'string' ? JSON.parse(query) : query;
} catch (e) {
  // surface a field-level validation error to the user with the offending text
}

Prevention

When it happens

Trigger: query = getNodeParameter('query', 0, {}) and if typeof query === 'string', JSON.parse(query) runs in a try/catch. A SyntaxError from JSON.parse triggers NodeOperationError 'Failed to parse query: <message>'. Fires when the user provides free text or malformed JSON in the query field.

Common situations: User types plain-language text into the query field instead of a JSON object; missing braces/quotes/commas in hand-written JSON; expression that resolves to undefined or non-JSON string; trailing commas.

Understand the failure class

Related errors


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