can1357/oh-my-pi · error · ValidationError

Unknown user content type

Error message

Unknown user content type

What it means

When converting a UserMessage into Bedrock's wire format, each content block's type is switched over. Only text, thinking-related, and image block types are supported for the user role; any other content type (e.g. tool_call, audio, document) hits the default branch and throws a ValidationError. This is a client-side pre-flight guard — nothing was sent to AWS.

Source

Thrown at packages/ai/src/providers/amazon-bedrock.ts:860

				if (typeof m.content === "string") {
					// Skip empty user messages
					if (!m.content || m.content.trim() === "") continue;
					result.push({ role: "user", content: [{ text: m.content.toWellFormed() }] });
				} else {
					const contentBlocks: UserContent[] = [];
					for (const c of m.content) {
						switch (c.type) {
							case "text": {
								const text = c.text.toWellFormed();
								if (text.trim().length === 0) continue;
								contentBlocks.push({ text });
								break;
							}
							case "image":
								contentBlocks.push({ image: createImageBlock(c.mimeType, c.data) });
								break;
							default:
								throw new AIError.ValidationError("Unknown user content type");
						}
					}
					// Skip message if all blocks filtered out
					if (contentBlocks.length === 0) continue;
					result.push({ role: "user", content: contentBlocks });
				}
				break;
			case "assistant": {
				// Skip assistant messages with empty content (e.g., from aborted requests)
				// Bedrock rejects messages with empty content arrays
				if (m.content.length === 0) continue;
				const contentBlocks: AssistantContent[] = [];
				for (const c of m.content) {
					switch (c.type) {
						case "text":
							// Skip empty text blocks
							if (c.text.trim().length === 0) continue;
							contentBlocks.push({ text: c.text.toWellFormed() });

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the user message content array and remove/convert unsupported block types before calling the provider
  2. Use the provider's tool-result message representation for tool outputs instead of embedding them as generic user blocks
  3. Filter or map content blocks: keep only text and image blocks (with image/jpeg, png, gif, webp MIME types) for user messages
  4. If you need a new block type supported, extend the conversion switch in amazon-bedrock.ts rather than passing it through

Example fix

// before
messages.push({ role: "user", content: [{ type: "document", mediaType: "application/pdf", data }] });
// after: send only supported user blocks
messages.push({
  role: "user",
  content: [{ type: "text", text: "See attached notes" }],
});
// or supply tool output via the tool-result message role
Defensive patterns

Strategy: validation

Validate before calling

const USER_BLOCK_TYPES = new Set(["text", "image"]);
function hasOnlySupportedUserBlocks(msg: Context): boolean {
  return msg.role !== "user" || msg.content.every(c => USER_BLOCK_TYPES.has(c.type));
}
// run over all user messages before calling the provider
const bad = context.find(m => !hasOnlySupportedUserBlocks(m));
if (bad) throw new Error(`User message contains unsupported block type: ${bad.content.map(c => c.type).join(",")}`);

Type guard

function isSupportedUserBlock(c: ContentBlock): c is TextBlock | ImageBlock {
  return c.type === "text" || c.type === "image";
}

Try / catch

try {
  await provider.stream(context);
} catch (err) {
  if (err instanceof AIError.ValidationError && err.message === "Unknown user content type") {
    // sanitize and retry once with text/image blocks only
    return provider.stream(context.map(sanitizeUserMessage));
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the Bedrock provider with a user message whose content array contains a block type other than text/image — for example passing tool-result or tool-call content as plain user content instead of using the proper tool message path.

Common situations: Building message histories manually and including unsupported block types; porting conversation state from another provider whose user-role blocks (e.g. audio, documents) Bedrock conversion doesn't map; a bug in middleware that rewrites user messages.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/3ef88038ba999506. Report an issue: GitHub.