zylon-ai/private-gpt · error · ValueError
Block cannot be None
Error message
Block cannot be None
What it means
Second pass of block validation in ChatBody: while cross-checking tool_use/tool_result blocks across messages, any None block inside a list content raises this error. It is the same null-block defect as error 329, caught in the tool-consistency loop (which runs after basic validation and can be the first place a null slips through if the earlier loop shape differs).
Source
Thrown at private_gpt/server/chat/chat_models.py:391
# Check unique tools
if self.tools:
tool_names = [tool.name for tool in self.tools]
if len(tool_names) != len(set(tool_names)):
raise ValueError(
"Duplicate tool names found in the tools list."
f" Provided tools: {self.tools}"
f" Unique tool names: {set(tool_names)}"
)
# Check tool use and result blocks
tool_uses_ids: set[str] = set()
tool_results_ids: set[str] = set()
for message in self.messages:
if isinstance(message.content, list):
for block in message.content:
if block is None:
raise ValueError("Block cannot be None")
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":View on GitHub (pinned to 4a030776a3)
Solutions
- Sanitize content lists before sending: drop None blocks.
- Fix block (de)serialization so every entry is a valid block object or removed.
- On load from storage, repair histories: [b for b in content if b is not None].
Example fix
# before msg.content = stored_blocks # may contain None # after msg.content = [b for b in stored_blocks if b is not None]
Defensive patterns
Strategy: validation
Validate before calling
for m in messages:
if isinstance(m.get('content'), list):
m['content'] = [b for b in m['content'] if b is not None] Type guard
def no_null_blocks(msgs: list[dict]) -> bool:
return all(
all(b is not None for b in m['content'])
for m in msgs if isinstance(m.get('content'), list)
) Try / catch
except ValidationError as e:
if 'Block cannot be None' in str(e):
strip_null_blocks(messages); retry()
else:
raise Prevention
- Repair stored histories on load (drop null blocks)
- Never append placeholder nulls during block streaming
- Fuzz-test serializers with missing optional blocks
When it happens
Trigger: content arrays containing null alongside tool blocks, e.g. [null, ToolResultBlock(...)]; deserialized stored conversations with sparse block arrays; client SDKs emitting null for unsupported block types in tool loops.
Common situations: Persistent chat stores that leave null placeholders for deleted blocks; partial JSON round-trips of tool conversations; race conditions appending blocks while serializing.
Related errors
- Block cannot be None: {message}
- TOOL_NAME_CONFLICT
- mistral-common only supports function tools.
- Database query tool requires at least one SQL database artif
- Semantic search tool requires an ingested artifact context.
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/03b8dd826553e82c.
Report an issue: GitHub.