n8n-io/n8n · error · NodeOperationError

Invalid message type. Only imageBinary and imageUrl are supp

Error message

Invalid message type. Only imageBinary and imageUrl are supported

What it means

createImageMessage throws a NodeOperationError when message.messageType is neither 'imageBinary' nor 'imageUrl'. The function only knows how to construct an image content block for a HumanMessage, so any other message type value is rejected before any work begins.

Source

Thrown at packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/methods/imageUtils.ts:38

	}
	return `data:${binaryData.mimeType};base64,${bufferData.toString('base64')}`;
}

/**
 * Creates a human message with image content from either binary data or URL
 */
export async function createImageMessage({
	context,
	itemIndex,
	message,
}: {
	context: IExecuteFunctions;
	itemIndex: number;
	message: MessageTemplate;
}): Promise<HumanMessage> {
	// Validate message type
	if (message.messageType !== 'imageBinary' && message.messageType !== 'imageUrl') {
		throw new NodeOperationError(
			context.getNode(),
			'Invalid message type. Only imageBinary and imageUrl are supported',
		);
	}

	const detail = message.imageDetail === 'auto' ? undefined : message.imageDetail;

	// Handle image URL case
	if (message.messageType === 'imageUrl' && message.imageUrl) {
		return new HumanMessage({
			content: [
				{
					type: 'image_url',
					image_url: {
						url: message.imageUrl,
						detail,
					},
				},

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Open the Basic LLM Chain 'Messages' setting and confirm each human message's messageType is exactly 'imageBinary' or 'imageUrl'.
  2. If the message should be plain text, set the message type so promptUtils does not route it to createImageMessage (i.e. leave messageType as 'text').
  3. Recreate the message row from scratch instead of editing a stale value to avoid hidden fixedCollection state.
  4. Check the node typeVersion; workflows from older versions may need to be migrated/re-added.

Example fix

// before
if (message.messageType !== 'imageBinary' && message.messageType !== 'imageUrl') {
  throw new NodeOperationError(context.getNode(), 'Invalid message type. Only imageBinary and imageUrl are supported');
}

// after — list the accepted values in the error so the user can self-correct
const VALID = ['imageBinary', 'imageUrl'] as const;
if (!VALID.includes(message.messageType as any)) {
  throw new NodeOperationError(context.getNode(), {
    message: `Invalid message type '${message.messageType}'. Expected one of: ${VALID.join(', ')}.`,
    itemIndex,
  });
}
Defensive patterns

Strategy: validation

Validate before calling

const VALID_IMAGE_MESSAGE_TYPES = new Set(['imageBinary', 'imageUrl']);
function isValidImageMessageType(t: string): boolean {
  return VALID_IMAGE_MESSAGE_TYPES.has(t);
}
// before saving the message template
if (!isValidImageMessageType(message.messageType)) {
  throw new Error(`messageType must be imageBinary or imageUrl, got ${message.messageType}`);
}

Type guard

function isImageMessageType(t: unknown): t is 'imageBinary' | 'imageUrl' {
  return t === 'imageBinary' || t === 'imageUrl';
}

Prevention

When it happens

Trigger: A message template configured on the Basic LLM Chain has its type set to 'human' (so it routes into createImageMessage via promptUtils) but its messageType is 'text', 'audio', or some legacy/typo value, rather than 'imageBinary' or 'imageUrl'.

Common situations: The user added a message row intended for text but the promptUtils routing dispatched it to createImageMessage, or a workflow exported from an older node version has a messageType value that no longer exists. A typo in a fixedCollection value (e.g. 'imageBinry') also triggers this.

Related errors


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