can1357/oh-my-pi · error · ValidationError

Unknown assistant content type

Error message

Unknown assistant content type

What it means

When converting an AssistantMessage into Bedrock's wire format, the switch over assistant content block types only supports text, toolCall, and (demoted) thinking blocks. Any other assistant-side block type falls through to the default branch and throws a ValidationError before any request reaches AWS. Notably, this converter deliberately demotes replayed thinking blocks to text so they can be safely replayed, but it has no mapping for other block kinds.

Source

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

									reasoningContent: {
										reasoningText: { text: c.thinking.toWellFormed(), signature: c.thinkingSignature },
									},
								});
							} else {
								// No signature was captured. Do NOT fall back to unsigned reasoningContent here:
								// a model streaming reasoningContent does not imply it accepts reasoningContent
								// echoed back in a request. Amazon Nova streams unsigned reasoning just fine but
								// rejects it on replay with HTTP 400 "User messages cannot contain reasoning
								// content. Please remove the reasoning content and try again.", which wedges the
								// agent loop on every turn after the first. Demote to plain text instead — the
								// content survives, just no longer typed as a reasoning block. This matches how
								// every other provider (Anthropic, Google, OpenAI-completions) handles thinking
								// blocks it can't safely replay.
								contentBlocks.push({ text: renderDemotedThinking(model.id, c.thinking) });
							}
							break;
						default:
							throw new AIError.ValidationError("Unknown assistant content type");
					}
				}
				// Skip if all content blocks were filtered out
				if (contentBlocks.length === 0) continue;
				result.push({ role: "assistant", content: contentBlocks });
				break;
			}
			case "toolResult": {
				// Collect all consecutive toolResult messages into a single user message —
				// Bedrock requires all tool results to be in one message.
				const toolResults: ToolResultBlockWire[] = [];
				toolResults.push({
					toolResult: {
						toolUseId: normalizeToolCallId(m.toolCallId),
						content: m.content.map(c =>
							c.type === "image"
								? { image: createImageBlock(c.mimeType, c.data) }
								: { text: c.text.toWellFormed() },

View on GitHub (pinned to 9690622007)

Solutions

  1. Sanitize assistant messages before replay: keep only text, toolCall, and thinking blocks
  2. Strip or re-emit non-text assistant blocks as text summaries when migrating history from another provider
  3. Check that transcript persistence isn't corrupting block type discriminators (e.g. saving/loading changed the shape)
  4. If a legitimate Bedrock-supported assistant block is missing, extend the conversion switch in amazon-bedrock.ts

Example fix

// before: replaying foreign assistant blocks verbatim
history.push(foreignAssistantMessage); // contains { type: "image", ... }
// after: convert to text before sending
history.push({
  role: "assistant",
  content: foreignAssistantMessage.content
    .filter(c => c.type === "text" || c.type === "toolCall" || c.type === "thinking"),
});
Defensive patterns

Strategy: validation

Validate before calling

const ASSISTANT_BLOCK_TYPES = new Set(["text", "toolCall", "thinking"]);
function sanitizeAssistant(m: Context): Context {
  if (m.role !== "assistant") return m;
  return { ...m, content: m.content.filter(c => ASSISTANT_BLOCK_TYPES.has(c.type)) };
}
const safeContext = context.map(sanitizeAssistant);

Type guard

function isSupportedAssistantBlock(c: ContentBlock): boolean {
  return c.type === "text" || c.type === "toolCall" || c.type === "thinking";
}

Try / catch

try {
  return await provider.complete(context);
} catch (err) {
  if (err instanceof AIError.ValidationError && err.message === "Unknown assistant content type") {
    logger.warn("dropping unsupported assistant blocks for bedrock replay");
    return provider.complete(context.map(sanitizeAssistant));
  }
  throw err;
}

Prevention

When it happens

Trigger: Replaying a conversation to Bedrock where an assistant message contains a content block type the Bedrock converter does not handle (e.g. image in assistant role, or an exotic custom block) — typically when reconstructing history that was generated by a different provider.

Common situations: Switching a session from another provider to Bedrock mid-conversation; resuming stored transcripts that contain assistant blocks not produced by this converter; programmatic construction of assistant messages with wrong block types.

Related errors


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