spring-projects/spring-ai · error · IllegalArgumentException

Unsupported message type:

Error message

Unsupported message type: 

What it means

BedrockProxyChatModel.createRequest maps Spring AI Message objects to Bedrock Converse API messages. Each MessageType has a known mapping (user, assistant, system, tool); when a message carries a MessageType the converter does not handle, it throws IllegalArgumentException 'Unsupported message type: ' + the type. This usually means a custom or unrecognized message subtype reached the request builder.

Source

Thrown at models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java:361

				}

				instructionMessages
					.add(Message.builder().content(contentBlocks).role(ConversationRole.ASSISTANT).build());
			}
			else if (message.getMessageType() == MessageType.TOOL) {
				List<ContentBlock> contentBlocks = new ArrayList<>(
						((ToolResponseMessage) message).getResponses().stream().map(toolResponse -> {
							ToolResultBlock toolResultBlock = ToolResultBlock.builder()
								.toolUseId(toolResponse.id())
								.content(ToolResultContentBlock.builder().text(toolResponse.responseData()).build())
								.build();
							return ContentBlock.fromToolResult(toolResultBlock);
						}).toList());

				instructionMessages.add(Message.builder().content(contentBlocks).role(ConversationRole.USER).build());
			}
			else {
				throw new IllegalArgumentException("Unsupported message type: " + message.getMessageType());
			}
		}

		// Determine if system message caching should be applied
		boolean shouldCacheSystem = cacheOptions != null
				&& (cacheOptions.getStrategy() == BedrockCacheStrategy.SYSTEM_ONLY
						|| cacheOptions.getStrategy() == BedrockCacheStrategy.SYSTEM_AND_TOOLS);

		if (logger.isDebugEnabled() && cacheOptions != null) {
			logger.debug("Cache strategy: " + cacheOptions.getStrategy() + ", shouldCacheSystem: " + shouldCacheSystem);
		}

		List<org.springframework.ai.chat.messages.Message> systemMessageList = prompt.getInstructions()
			.stream()
			.filter(m -> m.getMessageType() == MessageType.SYSTEM)
			.toList();

		// With multi-block system caching, place the cache point after the

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Log message.getMessageType() for all messages in the Prompt to find the offending one.
  2. Ensure every message is created via UserMessage, AssistantMessage, SystemMessage, or ToolResponseMessage so the type is one Bedrock supports.
  3. Filter/convert foreign message types before constructing the Prompt for Bedrock.
  4. Upgrade spring-ai-bedrock-converse if a supported type is being rejected (framework bug).

Example fix

// before
messages.add(myCustomMessage); // MessageType not handled by Bedrock
// after
if (myCustomMessage.getMessageType() == MessageType.USER
        || myCustomMessage.getMessageType() == MessageType.ASSISTANT) {
    messages.add(myCustomMessage);
} else {
    messages.add(new UserMessage(myCustomMessage.getText()));
}
Defensive patterns

Strategy: type-guard

Validate before calling

static Set<MessageType> SUPPORTED = Set.of(MessageType.USER, MessageType.ASSISTANT, MessageType.SYSTEM, MessageType.TOOL);
static boolean isBedrockSupported(Message m) {
    return m != null && SUPPORTED.contains(m.getMessageType());
}

Type guard

static Optional<MessageType> bedrockMessageType(Message m) {
    return Optional.ofNullable(m).map(Message::getMessageType)
        .filter(t -> t == MessageType.USER || t == MessageType.ASSISTANT
            || t == MessageType.SYSTEM || t == MessageType.TOOL);
}

Try / catch

try {
    return bedrockModel.call(prompt);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unsupported message type")) {
        log.error("Message with unhandled type in prompt: {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing a Message whose getMessageType() returns a value outside the handled set into BedrockProxyChatModel.call()/stream() — e.g. a custom Message implementation, a deprecated message type, or framework messages (like function/tool callback results of an unexpected shape) constructed manually.

Common situations: Mixing messages from another model adapter into a Bedrock conversation; upgrading Spring AI where a new MessageType was introduced while code still assumes old types; hand-building Prompt messages with a wrong MessageType enum.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/70def85a66c05fa7. Report an issue: GitHub.