n8n-io/n8n · error · NodeOperationError

Model output doesn't fit required format

Error message

Model output doesn't fit required format

What it means

Thrown by the Text Classifier when a Promise.allSettled batch promise rejected, continueOnFail is false, and the rejection could not be re-interpreted by wrapLangChainParserError into a softer form. The LLM output did not match the StructuredOutputParser schema (the boolean flags per category), so the parser rejected it.

Source

Thrown at packages/@n8n/nodes-langchain/nodes/chains/TextClassifier/TextClassifier.node.ts:279

						multiClassPrompt,
						fallbackPrompt,
					);
				});

				const batchResults = await Promise.allSettled(batchPromises);

				batchResults.forEach((response, batchItemIndex) => {
					const index = i + batchItemIndex;
					if (response.status === 'rejected') {
						const error = wrapLangChainParserError(response.reason, this.getNode(), index);
						if (this.continueOnFail()) {
							returnData[0].push({
								json: { error: error.message },
								pairedItem: { item: index },
							});
							return;
						} else {
							throw new NodeOperationError(this.getNode(), error);
						}
					} else {
						const output = response.value;
						const item = items[index];

						categories.forEach((cat, idx) => {
							if (output[cat.category]) returnData[idx].push(item);
						});

						if (fallback === 'other' && output.fallback)
							returnData[returnData.length - 1].push(item);
					}
				});

				// Add delay between batches if not the last batch
				if (i + batchSize < items.length && delayBetweenBatches > 0) {
					await sleep(delayBetweenBatches);
				}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Enable Continue On Fail so failing items return an error JSON rather than aborting the batch.
  2. Reduce the number of categories or make their descriptions clearer and mutually exclusive.
  3. Use a stronger instruction-tuned model and lower the temperature.
  4. Restore the default system prompt template if it was customized.

Example fix

// before — aborts whole run on first rejection
if (response.status === 'rejected') {
  const error = wrapLangChainParserError(response.reason, this.getNode(), index);
  if (this.continueOnFail()) {
    returnData[0].push({ json: { error: error.message }, pairedItem: { item: index } });
    return;
  } else {
    throw new NodeOperationError(this.getNode(), error);
  }
}

// after — keep raw reason for debugging
if (response.status === 'rejected') {
  const error = wrapLangChainParserError(response.reason, this.getNode(), index);
  returnData[0].push({ json: { error: error.message, raw: String(response.reason) }, pairedItem: { item: index } });
  if (!this.continueOnFail()) {
    throw new NodeOperationError(this.getNode(), error);
  }
  return;
}
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-flight: confirm model and categories are sound
if (!llm) throw new Error('Connect a chat model');
if (categories.length === 0) throw new Error('Add categories first');

Try / catch

try {
  const out = await parser.parse(llmOutput);
} catch (e) {
  // Continue per-item with an error JSON so the batch survives
  returnData[0].push({ json: { error: (e as Error).message }, pairedItem: { item: index } });
}

Prevention

When it happens

Trigger: For an item in the batch, the LLM returned text that could not be parsed into the expected {category: boolean} structure. allSettled marks it rejected; with continueOnFail off, the wrapped error becomes a NodeOperationError.

Common situations: LLM returns free text or hallucinated category names; schema is ambiguous; weak model; high temperature; too many categories confusing the model; customized system prompt template broke the format.

Related errors


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