Misc. bug: Complex tool calling schema causes an "Unrecognized Schema" exception
Name and Version
./llama-cli --version
ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no
ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no
ggml_cuda_init: found 1 CUDA devices:
Device 0: NVIDIA GeForce RTX 4070, compute capability 8.9, VMM: yes
load_backend: loaded CUDA backend from llama.cpp\ggml-cuda.dll
load_backend: loaded RPC backend from llama.cpp\ggml-rpc.dll
load_backend: loaded CPU backend from llama.cpp\ggml-cpu-alderlake.dll
version: 5684 (6adc3c3e)
built with clang version 18.1.8 for x86_64-pc-windows-msvc
Operating systems
Windows
Which llama.cpp modules do you know to be affected?
llama-server
Command line
llama-server --port 5001 --no-webui --flash-attn --threads 8 --model models/unsloth/qwen-3/Qwen3-14B-UD-Q6_K_XL.gguf --jinja --n-gpu-layers 27 --ctx-size 8192 --temp 0.6 --top_k 20 --top_p 0.8 --min_p 0.01 --verbose
Problem description & steps to reproduce
When llama-server encounters complex JSON schemas for tool calling, particularly those including the not and anyOf options, it causes an Unrecognized Schema exception which results in the generation failing.
In my case, this occurred while trying to use MCP with LibreChat and MarkusPfundstein's mcp-obsidian MCP server. The cause of the problem appears to be LibreChat's verbose tool calling JSON schemas, which other inference providers such as TabbyAPI and Gemini are capable of parsing.
To reproduce:
- Start llama-server with any tool-calling capable model such as Qwen3
- Using a frontend like LibreChat, attempt to run an MCP-enabled generation with
mcp-obsidianormcp-filesystem - The server should emit an Unrecognized Schema error
First Bad Commit
No response
Relevant log output
srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 500
srv log_server_r: request: {
"model": "default-model",
"stream": true,
"tools": [
{
"type": "function",
"function": {
"name": "obsidian_list_files_in_dir_mcp_mcp-obsidian",
"description": "Lists all files and directories that exist in a specific Obsidian directory.",
"parameters": {
"type": "object",
"properties": {
"dirpath": {
"type": "string",
"description": "Path to list files from (relative to your vault root). Note that empty directories will not be returned."
}
},
"required": [
"dirpath"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_list_files_in_vault_mcp_mcp-obsidian",
"description": "Lists all files and directories in the root directory of your Obsidian vault.",
"parameters": {
"type": "object",
"properties": {},
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_get_file_contents_mcp_mcp-obsidian",
"description": "Return the content of a single file in your vault.",
"parameters": {
"type": "object",
"properties": {
"filepath": {
"type": "string",
"description": "Path to the relevant file (relative to your vault root)."
}
},
"required": [
"filepath"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_simple_search_mcp_mcp-obsidian",
"description": "Simple search for documents matching a specified text query across all files in the vault. \n Use this tool when you want to do a simple text search",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Text to a simple search for in the vault."
},
"context_length": {
"anyOf": [
{
"anyOf": [
{
"not": {}
},
{
"description": "How much context to return around the matching string (default: 100)"
}
],
"description": "How much context to return around the matching string (default: 100)"
},
{
"type": "null"
}
],
"description": "How much context to return around the matching string (default: 100)"
}
},
"required": [
"query"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_patch_content_mcp_mcp-obsidian",
"description": "Insert content into an existing note relative to a heading, block reference, or frontmatter field.",
"parameters": {
"type": "object",
"properties": {
"filepath": {
"type": "string",
"description": "Path to the file (relative to vault root)"
},
"operation": {
"type": "string",
"enum": [
"append",
"prepend",
"replace"
],
"description": "Operation to perform (append, prepend, or replace)"
},
"target_type": {
"type": "string",
"enum": [
"heading",
"block",
"frontmatter"
],
"description": "Type of target to patch"
},
"target": {
"type": "string",
"description": "Target identifier (heading path, block reference, or frontmatter field)"
},
"content": {
"type": "string",
"description": "Content to insert"
}
},
"required": [
"filepath",
"operation",
"target_type",
"target",
"content"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_append_content_mcp_mcp-obsidian",
"description": "Append content to a new or existing file in the vault.",
"parameters": {
"type": "object",
"properties": {
"filepath": {
"type": "string",
"description": "Path to the file (relative to vault root)"
},
"content": {
"type": "string",
"description": "Content to append to the file"
}
},
"required": [
"filepath",
"content"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_delete_file_mcp_mcp-obsidian",
"description": "Delete a file or directory from the vault.",
"parameters": {
"type": "object",
"properties": {
"filepath": {
"type": "string",
"description": "Path to the file or directory to delete (relative to vault root)"
},
"confirm": {
"type": "boolean",
"description": "Confirmation to delete the file (must be true)"
}
},
"required": [
"filepath",
"confirm"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_complex_search_mcp_mcp-obsidian",
"description": "Complex search for documents using a JsonLogic query. \n Supports standard JsonLogic operators plus 'glob' and 'regexp' for pattern matching. Results must be non-falsy.\n\n Use this tool when you want to do a complex search, e.g. for all documents with certain tags etc.\n ",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "object",
"properties": {},
"additionalProperties": false,
"description": "JsonLogic query object. Example: {\"glob\": [\"*.md\", {\"var\": \"path\"}]} matches all markdown files"
}
},
"required": [
"query"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_batch_get_file_contents_mcp_mcp-obsidian",
"description": "Return the contents of multiple files in your vault, concatenated with headers.",
"parameters": {
"type": "object",
"properties": {
"filepaths": {
"type": "array",
"items": {
"type": "string",
"description": "Path to a file (relative to your vault root)"
},
"description": "List of file paths to read"
}
},
"required": [
"filepaths"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_get_periodic_note_mcp_mcp-obsidian",
"description": "Get current periodic note for the specified period.",
"parameters": {
"type": "object",
"properties": {
"period": {
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
"quarterly",
"yearly"
],
"description": "The period type (daily, weekly, monthly, quarterly, yearly)"
}
},
"required": [
"period"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_get_recent_periodic_notes_mcp_mcp-obsidian",
"description": "Get most recent periodic notes for the specified period type.",
"parameters": {
"type": "object",
"properties": {
"period": {
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
"quarterly",
"yearly"
],
"description": "The period type (daily, weekly, monthly, quarterly, yearly)"
},
"limit": {
"anyOf": [
{
"anyOf": [
{
"not": {}
},
{
"description": "Maximum number of notes to return (default: 5)"
}
],
"description": "Maximum number of notes to return (default: 5)"
},
{
"type": "null"
}
],
"description": "Maximum number of notes to return (default: 5)"
},
"include_content": {
"anyOf": [
{
"anyOf": [
{
"not": {}
},
{
"type": "boolean",
"description": "Whether to include note content (default: false)"
}
],
"description": "Whether to include note content (default: false)"
},
{
"type": "null"
}
],
"description": "Whether to include note content (default: false)"
}
},
"required": [
"period"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
},
{
"type": "function",
"function": {
"name": "obsidian_get_recent_changes_mcp_mcp-obsidian",
"description": "Get recently modified files in the vault.",
"parameters": {
"type": "object",
"properties": {
"limit": {
"anyOf": [
{
"anyOf": [
{
"not": {}
},
{
"description": "Maximum number of files to return (default: 10)"
}
],
"description": "Maximum number of files to return (default: 10)"
},
{
"type": "null"
}
],
"description": "Maximum number of files to return (default: 10)"
},
"days": {
"anyOf": [
{
"anyOf": [
{
"not": {}
},
{
"description": "Only include files modified within this many days (default: 90)"
}
],
"description": "Only include files modified within this many days (default: 90)"
},
{
"type": "null"
}
],
"description": "Only include files modified within this many days (default: 90)"
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
}
}
],
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "List the notes in my vault, please"
}
]
}
]
}
srv log_server_r: response: {"error":{"code":500,"message":"JSON schema conversion failed:\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"How much context to return around the matching string (default: 100)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"How much context to return around the matching string (default: 100)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"Maximum number of notes to return (default: 5)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"Maximum number of notes to return (default: 5)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"Maximum number of files to return (default: 10)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"Only include files modified within this many days (default: 90)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"Maximum number of files to return (default: 10)\"}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"description\":\"Only include files modified within this many days (default: 90)\"}","type":"server_error"}}
I can confirm this bug using Qwen3 models and enabling native tool calling against the latest master build of llama-server
This error might be related to a tool parameter missing "type". I'm encountering this error when enabling @bharathvaj/whois-mcp via mcpo, specifically the 3rd tool it returns (tool_whois_ip_post).
"type": "function",
"function": {
"type": "function",
"name": "tool_whois_tld_post",
"description": "Looksup whois information about the Top Level Domain (TLD)",
"parameters": {
"type": "object",
"properties": {
"tld": {
"type": "string",
"title": "Tld",
"description": ""
}
},
"required": [
"tld"
]
}
}
},
{
"type": "function",
"function": {
"type": "function",
"name": "tool_whois_ip_post",
"description": "Looksup whois information about the IP",
"parameters": {
"type": "object",
"properties": {
"ip": {
"title": "Ip",
"description": ""
}
},
"required": [
"ip"
]
}
}
},
response: {"error":{"code":500,"message":"JSON schema conversion failed:\nUnrecognized schema: {\"title\":\"Ip\",\"description\":\"\"}\nUnrecognized schema: {\"title\":\"Ip\",\"description\":\"\"}","type":"server_error"}}
I'm also experiencing when using librechat + MCP (smithery.ai). Definitely seems to be something with llama-server's handling of the tool calls. I tried the same request with OpenAI (gpt-4o-mini) and DeepSeek Chat (deepseek's API) and both worked.
The llama-server (B5918) error message:
srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 500
got exception: {"code":500,"message":"JSON schema conversion failed:\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"not\":{}}","type":"server_error"}
My llama-server command:
llama-server-latest
--host 127.0.0.1 --port 5802 --flash-attn -ngl 999 -ngld 999 --no-mmap
--cache-type-k q8_0 --cache-type-v q8_0
--model /path/to/models/Qwen_Qwen3-32B-Q4_K_L.gguf --ctx-size 32000
--no-context-shift --temp 0.6 --min-p 0 --top-k 20 --top-p 0.95 -ngl 99
--jinja --reasoning-format deepseek --reasoning-budget 0
Just adding a +1 that I also experience this issue with LibreChat, Llama.cpp, and Qwen. Switched to Ollama and no longer have the same issue. I'd much rather use llama.cpp and intend to switch back whenever this issue is hopefully resolved.
Testing this a bit - string parameters work but optional fields or integers seem to fail:
class QueryInput(BaseModel):
query: str = Field(..., description="Query to run")
@mcp.tool()
async def search(request: QueryInput) -> str:
""" Run a search. Returns Search Ran if successful"""
return "Search Ran"
The above succeeds, but if you add an int field the tool call fails
class QueryInput(BaseModel):
query: str = Field(..., description="Query to run")
result_count: int = Field(..., description="Number of results to return")
srv log_server_r: request: {"model":"Qwen3-4B-Instruct-2507","user":"68879a9e561c23027f99f0c8","stream":true,"tools":[{"type":"function","function":{"name":"search_mcp_duckduckgo","description":"Run a search. Returns Search Ran if successful","parameters":{"type":"object","properties":{"request":{"type":"object","properties":{"query":{"type":"string","description":"Query to run"},"result_count":{"description":"Number of results to return"}},"required":["query"],"additionalProperties":false}},"required":["request"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}],"messages":[{"role":"user","content":"Search for NYC"}]}
srv log_server_r: response: {"error":{"code":500,"message":"JSON schema conversion failed:\nUnrecognized schema: {\"description\":\"Number of results to return\"}\nUnrecognized schema: {\"description\":\"Number of results to return\"}","type":"server_error"}}
Additionally if you make a field optional it fails
class QueryInput(BaseModel):
query: str = Field(default="NYC", description="Query to run")
srv log_server_r: request: {"model":"Qwen3-4B-Instruct-2507","user":"68879a9e561c23027f99f0c8","stream":true,"tools":[{"type":"function","function":{"name":"search_mcp_duckduckgo","description":"Run a search. Returns Search Ran if successful","parameters":{"type":"object","properties":{"request":{"type":"object","properties":{"query":{"anyOf":[{"anyOf":[{"not":{}},{"type":"string","description":"Query to run"}],"description":"Query to run"},{"type":"null"}],"description":"Query to run"}},"additionalProperties":false}},"required":["request"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}],"messages":[{"role":"user","content":"what's the weather like in New York. Please provide 12 results"}]}
srv log_server_r: response: {"error":{"code":500,"message":"JSON schema conversion failed:\nUnrecognized schema: {\"not\":{}}\nUnrecognized schema: {\"not\":{}}","type":"server_error"}}
Patching https://github.com/ggml-org/llama.cpp/blob/b3e16665e14032d1276f9d0263acef8321b6f518/common/json-schema-to-grammar.cpp#L800
with
json schema_type = schema.contains("type") ? schema["type"] : "null";
allows the tool calls to run.
However, for some strange reason, at least in FastMCP, there is no type information provided for integers so LLMs don't know what type to set the field as unless you document it elsewhere
Not sure what this breaks but at least it's a temporary workaround
not stale, still an issue in the latest version
I’m experiencing the same problem when using the Goose + Ramalama + gpt-oss 20b setup.
build: 1 (b0d5299) with cc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-7) for x86_64-redhat-linux
On the Ramalama side:
llama-server -v --port 8080 --model /mnt/models/gpt-oss-20b-mxfp4.gguf --no-warmup --jinja --chat-template-file /mnt/models/chat_template_extracted --log-colors on --alias gpt-oss-64k --temp 0.2 --cache-reuse 256 --ctx-size 64000 --flash-attn on -ngl 999 --threads 16 --host 0.0.0.0
SecurityLabelDisable=true
In Goose, it send function call like this:
{
"function": {
"description": "Create tasks with instructions or prompt. For simple tasks, only include the instructions field. Extensions control: omit field = use all current extensions; empty array [] = no extensions; array with names = only those extensions. Specify extensions as shortnames (the prefixes for your tools). Specify return_last_only as true and have your subagent summarize its work in its last message to conserve your own context. Optional: title, description, extensions, settings, retry, response schema, context, activities. Arrays for multiple tasks.",
"name": "dynamic_task__create_task",
"parameters": {
"properties": {
"execution_mode": {
"description": "How to execute multiple tasks (default: parallel for multiple tasks, sequential for single task)",
"enum": [
"sequential",
"parallel"
],
"type": "string"
},
"task_parameters": {
"description": "Array of tasks. Each needs 'instructions' OR 'prompt'.",
"items": {
"anyOf": [
{
"required": [
"instructions"
]
},
{
"required": [
"prompt"
]
}
],
"properties": {
"activities": {
"items": {
"type": "string"
},
"type": "array"
},
"context": {
"items": {
"type": "string"
},
"type": "array"
},
"description": {
"type": "string"
},
"extensions": {
"items": {
"type": "object"
},
"type": "array"
},
"instructions": {
"description": "Task instructions",
"type": "string"
},
"parameters": {
"items": {
"type": "object"
},
"type": "array"
},
"prompt": {
"description": "Initial prompt",
"type": "string"
},
"response": {
"type": "object"
},
"retry": {
"type": "object"
},
"return_last_only": {
"description": "If true, return only the last message from the subagent (default: false, returns full conversation)",
"type": "boolean"
},
"settings": {
"type": "object"
},
"title": {
"type": "string"
}
},
"type": "object"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"task_parameters"
],
"type": "object"
}
},
"type": "function"
},
When invoking tools (tool calling), I also hit the same Unrecognized Schema error, while other requests work fine.
{
"error": {
"code": 500,
"message": "JSON schema conversion failed:\nUnrecognized schema: {\"required\":[\"instructions\"]}\nUnrecognized schema: {\"required\":[\"prompt\"]}\nUnrecognized schema: {\"required\":[\"instructions\"]}\nUnrecognized schema: {\"required\":[\"prompt\"]}",
"type": "server_error"
}
}
I just encountered this issue using llama.cpp server 2f68ce7c and Goose 1.12.1.
In the Goose discussion https://github.com/block/goose/issues/4815 DOsinga commented:
make sure that our OpenAI provider accepts everything and then produces a very specific output.
If I understand their comment correctly: for MCP to work reliably, interfaces will need to be as permissive as possible with JSON schema validation on the receiving side; while on the sending side, emitting JSON that complies rigorously with the spec.
I believe the superficial cause of the problem in the case of Goose is that it emits JSON that is slightly non-compliant by omitting type specifiers in some cases. And then llama-server complains when it tries to parse it but finds that it doesn't match the schema it expects. llama-server throws an error and the MCP-consumer chokes.
But it seems like there are lots of other MCP-consumers that encounter the same fundamental issue by emitting their own slightly-non-compliant JSON. I am seeing tickets in lots of separate projects about the same pattern of JSON schema validation problems.
In the end, since there are two parties to each of these JSON schema validation issues, I could see a situation in which no project claims responsibility for fixing this. That would be a problem for the overall functioning of MCP - even beyond the scope of llama.cpp server.
Since JSON schema is a key part of MCP, and since JSON schema is itself pretty broad and general, there are lots of almost-valid JSON inputs for any MCP-speaking service to handle...
I am also experiencing this issue with several clients and tool schema definitions. As far as I can tell, the jsonschema being generated is valid, but the problem is that the it can't be made into a grammar. I do not know the practical implications, but does it make sense to make grammar creation and enforcement optional? That way the grammar enforcement doesn't need to handle all possible jsonschemas, but you can still pass tool definitions to models and let the client deal with malformed tool calls.
Quick hack for Librechat anyOf -> not scheme error:
https://github.com/ggml-org/llama.cpp/blob/b8595b16e69e3029e06be3b8f6635f9812b2bc3f/common/json-schema-to-grammar.cpp#L824
Add this lines below:
std::vector<json> filtered_schemas;
for (const auto& alt : alt_schemas) {
if (alt.is_object() && alt.contains("not")) {
const auto& not_val = alt["not"];
if (not_val.is_object() && not_val.empty()) {
continue;
}
}
filtered_schemas.push_back(alt);
}
Modify this line https://github.com/ggml-org/llama.cpp/blob/b8595b16e69e3029e06be3b8f6635f9812b2bc3f/common/json-schema-to-grammar.cpp#L825 to:
return _add_rule(rule_name, _generate_union_rule(name, filtered_schemas));
In short, this code filters out not: {} from tree.
I am encountering the same issue when attempting to run the complex_inputs.py example from the official modelcontextprotocol/python-sdk repository.
Error Message
got exception: {"code":500,"message":"JSON schema conversion failed:\nError resolving ref #/$defs/ShrimpTank: $defs not in {\"properties\":{\"extra_names\":{\"items\":{\"type\":\"string\"},\"maxItems\":10,\"title\":\"Extra Names\",\"type\":\"array\"},\"tank\":{\"$ref\":\"#/$defs/ShrimpTank\"}},\"required\":[\"tank\",\"extra_names\"],\"type\":\"object\"}","type":"server_error"}
JSON Schema
{
"name": "name_shrimp",
"title": null,
"description": "List all shrimp names in the tank",
"inputSchema": {
"$defs": {
"Shrimp": {
"properties": {
"name": {
"maxLength": 10,
"title": "Name",
"type": "string"
}
},
"required": [
"name"
],
"title": "Shrimp",
"type": "object"
},
"ShrimpTank": {
"properties": {
"shrimp": {
"items": {
"$ref": "#/$defs/Shrimp"
},
"title": "Shrimp",
"type": "array"
}
},
"required": [
"shrimp"
],
"title": "ShrimpTank",
"type": "object"
}
},
"properties": {
"tank": {
"$ref": "#/$defs/ShrimpTank"
},
"extra_names": {
"items": {
"type": "string"
},
"maxItems": 10,
"title": "Extra Names",
"type": "array"
}
},
"required": [
"tank",
"extra_names"
],
"title": "name_shrimpArguments",
"type": "object"
},
"outputSchema": {
"properties": {
"result": {
"items": {
"type": "string"
},
"title": "Result",
"type": "array"
}
},
"required": [
"result"
],
"title": "name_shrimpOutput",
"type": "object"
},
"icons": null,
"annotations": null,
"meta": null
}
Complex Inputs MCP
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["mcp", "pydantic"]
# ///
from typing import Annotated
from pydantic import BaseModel, Field
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Shrimp Tank")
class ShrimpTank(BaseModel):
class Shrimp(BaseModel):
name: Annotated[str, Field(max_length=10)]
shrimp: list[Shrimp]
@mcp.tool()
def name_shrimp(
tank: ShrimpTank,
# You can use pydantic Field in function signatures for validation.
extra_names: Annotated[list[str], Field(max_length=10)],
) -> list[str]:
"""List all shrimp names in the tank"""
return [shrimp.name for shrimp in tank.shrimp] + extra_names
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Here's a patch derived from @HelloKS' suggestion:
diff --git a/common/json-schema-to-grammar.cpp b/common/json-schema-to-grammar.cpp
index 478aa1be7..ec0b3b73e 100644
--- a/common/json-schema-to-grammar.cpp
+++ b/common/json-schema-to-grammar.cpp
@@ -822,7 +822,17 @@ public:
return _add_rule(rule_name, _resolve_ref(schema["$ref"]));
} else if (schema.contains("oneOf") || schema.contains("anyOf")) {
std::vector<json> alt_schemas = schema.contains("oneOf") ? schema["oneOf"].get<std::vector<json>>() : schema["anyOf"].get<std::vector<json>>();
- return _add_rule(rule_name, _generate_union_rule(name, alt_schemas));
+ std::vector<json> filtered_schemas;
+ for (const auto& alt : alt_schemas) {
+ if (alt.is_object() && alt.contains("not")) {
+ const auto& not_val = alt["not"];
+ if (not_val.is_object() && not_val.empty()) {
+ continue;
+ }
+ }
+ filtered_schemas.push_back(alt);
+ }
+ return _add_rule(rule_name, _generate_union_rule(name, filtered_schemas));
} else if (schema_type.is_array()) {
std::vector<json> schema_types;
for (const auto & t : schema_type) {
Thank you for providing the lines that need changed. It works flawlessly.