zylon-ai/private-gpt · error · ValueError

TLDR blocks can only be used in assistant messages: {message

Error message

TLDR blocks can only be used in assistant messages: {message}

What it means

Raised while validating ChatMessages: a TLDRBlock (extended content block for conversation summaries) was found in a message whose role is not 'assistant'. TLDR blocks are only meaningful as part of assistant output, so the validator enforces role == 'assistant' for any message containing one.

Source

Thrown at private_gpt/server/chat/chat_models.py:410

                    elif isinstance(block, ToolUseBlock):
                        if message.role != "assistant":
                            raise ValueError(
                                f"Tool use blocks can only be used in assistant messages: {message}"
                            )
                        if block.id in tool_uses_ids:
                            raise ValueError(f"Duplicate tool use ID found: {block.id}")
                        tool_uses_ids.add(block.id)

                    elif isinstance(block, ToolResultBlock):
                        if block.tool_use_id not in tool_uses_ids:
                            raise ValueError(
                                f"Tool result block references an unknown tool use ID: {block.tool_use_id}"
                            )
                        tool_results_ids.add(block.tool_use_id)

                    elif isinstance(block, TLDRBlock):
                        if message.role != "assistant":
                            raise ValueError(
                                f"TLDR blocks can only be used in assistant messages: {message}"
                            )

        if tool_results_ids != tool_uses_ids:
            raise ValueError(
                "Tool result blocks must match the tool use IDs in the same message."
                f" Found tool use IDs: {tool_uses_ids}, but tool result IDs: {tool_results_ids}"
            )

        return self

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Move the TLDRBlock into an assistant-role message
  2. If you want to provide context/summary on the user side, send it as a plain text block instead of TLDRBlock

Example fix

# before
{"role": "user", "content": [{"type": "tldr", "text": "summary..."}]}

# after
{"role": "assistant", "content": [{"type": "tldr", "text": "summary..."}]}
Defensive patterns

Strategy: type-guard

Validate before calling

for m in messages:
    for b in (m.content or []):
        if isinstance(b, TLDRBlock) and m.role != "assistant":
            raise ValueError("move TLDRBlock to an assistant message")

Type guard

def tldr_blocks_in_assistant_messages(messages: list) -> bool:
    for m in messages:
        role = m.get("role") if isinstance(m, dict) else m.role
        blocks = m.get("content", []) if isinstance(m, dict) else (m.content or [])
        if any((b.get("type") if isinstance(b, dict) else getattr(b, "type", None)) == "tldr" for b in blocks) and role != "assistant":
            return False
    return True

Try / catch

try:
    ChatMessages(messages=msgs)
except ValueError as e:
    if "TLDR blocks" in str(e):
        move_tldr_blocks_to_assistant(msgs)
    else:
        raise

Prevention

When it happens

Trigger: Building a ChatMessages payload that puts a TLDRBlock into a 'user' or 'system' role message content list; e.g. a client trying to pre-seed a summary block on the user turn.

Common situations: Custom clients using the extended block protocol who assume summary blocks go with user context; copy-pasting block arrays between messages of different roles.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/3a4f32ecd6542a80. Report an issue: GitHub.