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
- Inspect the user message content array and remove/convert unsupported block types before calling the provider
- Use the provider's tool-result message representation for tool outputs instead of embedding them as generic user blocks
- Filter or map content blocks: keep only text and image blocks (with image/jpeg, png, gif, webp MIME types) for user messages
- 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
- Build user messages only from text and image blocks; route tool output through tool-result messages
- Add a schema/arktype check on messages at the boundary where they enter your app
- Test transcript round-trips (save/load) so block discriminators don't drift
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
- Unknown assistant content type
- Unknown message role
- Unknown image type: ${mimeType}
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3ef88038ba999506.
Report an issue: GitHub.