zylon-ai/private-gpt · error · ValueError
Block cannot be None: {message}
Error message
Block cannot be None: {message} What it means
When message.content is a list of content blocks, the ChatBody validator walks the blocks and rejects any None entry. A null block means malformed block serialization upstream (e.g. a block that failed to construct was appended as None); the error message includes the whole message for context.
Source
Thrown at private_gpt/server/chat/chat_models.py:321
if self.frequency_penalty and self.frequency_penalty < 0:
self.frequency_penalty = None
if self.seed and self.seed < 0:
self.seed = None
if self.max_tokens is not None and self.max_tokens <= 0:
self.max_tokens = None
if not self.messages:
raise ValueError("Messages cannot be empty")
for message in self.messages:
if not message.content:
raise ValueError(f"Message content cannot be empty: {message}")
if isinstance(message.content, list):
for block in message.content:
if block is None:
raise ValueError(f"Block cannot be None: {message}")
if self.messages[-1].role not in self._valid_last_message_roles:
raise ValueError(
f"Last message role must be one of {self._valid_last_message_roles}, but got {self.messages[-1].role}"
)
# Check tools and tool choice
if self.tools and self.tool_choice and self.tool_choice.type == "tool":
if not self.tools:
raise ValueError("Tool choice is set, but no tools are provided.")
if self.tool_choice.name not in [tool.name for tool in self.tools]:
raise ValueError(
f"Tool choice '{self.tool_choice}' is not in the provided tools."
)
if not self.tools and self.tool_context:
raise ValueError(
"Tool context is provided, but no tools are specified. "View on GitHub (pinned to 4a030776a3)
Solutions
- Filter nulls out of content arrays before sending: content=[b for b in blocks if b is not None].
- Fix the block serialization so unsupported blocks are skipped, not emitted as null.
- Validate stored history on load and drop/repair null blocks.
Example fix
# before content=[block for block in raw_blocks] # raw_blocks may contain None # after content=[block for block in raw_blocks if block 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 blocks_valid(content: list | str) -> bool:
if isinstance(content, list):
return all(b is not None for b in content)
return bool(content) Try / catch
except ValidationError as e:
if 'Block cannot be None' in str(e):
strip_null_blocks(messages); retry_request()
else:
raise Prevention
- Never store chat history with null block placeholders
- Sanitize deserialized histories before re-sending
- Skip unsupported blocks at serialization time instead of emitting null
When it happens
Trigger: Content arrays containing literal null: {"role":"user","content":[null, {"type":"text","text":"hi"}]}; JSON built by mapping over blocks where one element failed conversion to None; deserializing stored conversations with missing block entries.
Common situations: Storing chat history as sparse arrays (deleted blocks become null); client SDKs that emit null for unsupported block types; partial block JSON round-trips.
Related errors
- Block cannot be None
- Messages cannot be empty
- Message content cannot be empty: {message}
- Last message role must be one of {self._valid_last_message_r
- Tool choice '{self.tool_choice}' is not in the provided tool
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/cac42e9c7cab6645.
Report an issue: GitHub.